Re: [COMMITTERS] pgsql: Fix NUMERIC modulus to properly truncate - Mailing list pgsql-hackers

From Bruce Momjian
Subject Re: [COMMITTERS] pgsql: Fix NUMERIC modulus to properly truncate
Date
Msg-id 200506150137.j5F1boe14413@candle.pha.pa.us
Whole thread Raw
In response to Re: [COMMITTERS] pgsql: Fix NUMERIC modulus to properly  (Paul Tillotson <pntil@shentel.net>)
Responses Re: [COMMITTERS] pgsql: Fix NUMERIC modulus to properly truncate
List pgsql-hackers
Have we made any decision on whether the old/new NUMERIC %(mod) code was
correct, and now to handle rounding?  Should we offer a non-rounding
division operator for NUMERIC?

---------------------------------------------------------------------------

Paul Tillotson wrote:
> Bruce Momjian wrote:
> 
> >Tom Lane wrote:
> >  
> >
> >>Christopher Kings-Lynne <chriskl@familyhealth.com.au> writes:
> >>    
> >>
> >>>>No, I don't think so.  It doesn't seem to be something that enough
> >>>>people use to risk the change in behavior --- it might break something
> >>>>that was working.  But, if folks want it backported we can do it.  It is
> >>>>only a change to properly do modulus for numeric.
> >>>>        
> >>>>
> >>>Well, from my point of view it's an absolute mathematical error - i'd 
> >>>backport it.  I can't see anyone relying on it :)
> >>>      
> >>>
> >>Doesn't this patch break the basic theorem that
> >>
> >>    a = trunc(a / b) * b + (a mod b)
> >>
> >>?  If division rounds and mod doesn't, you've got pretty serious issues.
> >>    
> >>
> >
> >Well, this is a good question.  In the equation above we assume '/' is
> >an integer division.  The problem with NUMERIC when used with zero-scale
> >operands is that the result is already _rounded_ to the nearest hole
> >number before it gets to trunc(), and that is why we used to get
> >negative modulus values.  I assume the big point is that we don't offer
> >any way for users to get a NUMERIC division without rounding.
> >
> >With integers, we always round down to the nearest whole number on
> >division;  float doesn't offer a modulus operator, and C doesn't support
> >it either.
> >
> >We round NUMERICs to the specific scale because we want to give the most
> >accurate value:
> >
> >    test=> select 100000000000000000000000::numeric(24,0) /
> >    11::numeric(24,0);
> >            ?column?
> >    ------------------------
> >     9090909090909090909091
> >
> >The actual values is:
> >                                --
> >     9090909090909090909090.90
> >
> >But the problem is that the equation at the top assumes the division is
> >not rounded.  Should we supply a NUMERIC division operator that doesn't
> >round?  integer doesn't need it, and float doesn't have the accurate
> >precision needed for modulus operators.  The user could supply some
> >digits in the division:
> >    
> >    test=> select 100000000000000000000000::numeric(30,6) /
> >    11::numeric(24,0);
> >               ?column?
> >    -------------------------------
> >     9090909090909090909090.909091
> >    (1 row)
> >
> >but there really is no _right_ value to prevent rounding (think
> >0.9999999).  A non-rounding NUMERIC division would require duplicating
> >numeric_div() but with a false for 'round', and adding operators.
> >
> >  
> >
> I would prefer that division didn't round, as with integers.  You can 
> always calculate your result to 1 more decimal place and then round, but 
> there is no way to unround a rounded result.
> 
> Tom had asked whether PG passed the regression tests if we change the 
> round_var() to a trunc_var() at the end of the function div_var().
> 
> It does not pass, but I think that is because the regression test is 
> expecting that division will round up.  (Curiously, the regression test 
> for "numeric" passes, but the regression test for aggregation--sum() I 
> think--is the one that fails.)  I have attached the diffs here if anyone 
> is interested.
> 
> Regards,
> Paul Tillotson
> 

> *** ./expected/aggregates.out    Sun May 29 19:58:43 2005
> --- ./results/aggregates.out    Mon Jun  6 21:01:11 2005
> ***************
> *** 10,16 ****
>   SELECT avg(a) AS avg_32 FROM aggtest WHERE a < 100;
>          avg_32        
>   ---------------------
> !  32.6666666666666667
>   (1 row)
>   
>   -- In 7.1, avg(float4) is computed using float8 arithmetic.
> --- 10,16 ----
>   SELECT avg(a) AS avg_32 FROM aggtest WHERE a < 100;
>          avg_32        
>   ---------------------
> !  32.6666666666666666
>   (1 row)
>   
>   -- In 7.1, avg(float4) is computed using float8 arithmetic.
> 
> ======================================================================
> 

> test boolean              ... ok
> test char                 ... ok
> test name                 ... ok
> test varchar              ... ok
> test text                 ... ok
> test int2                 ... ok
> test int4                 ... ok
> test int8                 ... ok
> test oid                  ... ok
> test float4               ... ok
> test float8               ... ok
> test bit                  ... ok
> test numeric              ... ok
> test strings              ... ok
> test numerology           ... ok
> test point                ... ok
> test lseg                 ... ok
> test box                  ... ok
> test path                 ... ok
> test polygon              ... ok
> test circle               ... ok
> test date                 ... ok
> test time                 ... ok
> test timetz               ... ok
> test timestamp            ... ok
> test timestamptz          ... ok
> test interval             ... ok
> test abstime              ... ok
> test reltime              ... ok
> test tinterval            ... ok
> test inet                 ... ok
> test comments             ... ok
> test oidjoins             ... ok
> test type_sanity          ... ok
> test opr_sanity           ... ok
> test geometry             ... ok
> test horology             ... ok
> test insert               ... ok
> test create_function_1    ... ok
> test create_type          ... ok
> test create_table         ... ok
> test create_function_2    ... ok
> test copy                 ... ok
> test constraints          ... ok
> test triggers             ... ok
> test create_misc          ... ok
> test create_aggregate     ... ok
> test create_operator      ... ok
> test create_index         ... ok
> test inherit              ... ok
> test vacuum               ... ok
> test create_view          ... ok
> test sanity_check         ... ok
> test errors               ... ok
> test select               ... ok
> test select_into          ... ok
> test select_distinct      ... ok
> test select_distinct_on   ... ok
> test select_implicit      ... ok
> test select_having        ... ok
> test subselect            ... ok
> test union                ... ok
> test case                 ... ok
> test join                 ... ok
> test aggregates           ... FAILED
> test transactions         ... ok
> test random               ... ok
> test portals              ... ok
> test arrays               ... ok
> test btree_index          ... ok
> test hash_index           ... ok
> test update               ... ok
> test namespace            ... ok
> test privileges           ... ok
> test misc                 ... ok
> test select_views         ... ok
> test portals_p2           ... ok
> test rules                ... ok
> test foreign_key          ... ok
> test cluster              ... ok
> test limit                ... ok
> test plpgsql              ... ok
> test copy2                ... ok
> test temp                 ... ok
> test domain               ... ok
> test rangefuncs           ... ok
> test prepare              ... ok
> test without_oid          ... ok
> test conversion           ... ok
> test truncate             ... ok
> test alter_table          ... ok
> test sequence             ... ok
> test polymorphism         ... ok
> test rowtypes             ... ok
> test stats                ... ok
> test tablespace           ... ok

--  Bruce Momjian                        |  http://candle.pha.pa.us pgman@candle.pha.pa.us               |  (610)
359-1001+  If your life is a hard drive,     |  13 Roberts Road +  Christ can be your backup.        |  Newtown Square,
Pennsylvania19073
 


pgsql-hackers by date:

Previous
From: Bruce Momjian
Date:
Subject: Re: [COMMITTERS] pgsql: Add BETWEEN SYMMETRIC.
Next
From: "John Hansen"
Date:
Subject: LGPL