Re: [HACKERS] [COMMITTERS] pgsql: Fix NUMERIC modulus to properly truncate

2005-06-24 Thread Bruce Momjian

With no conclusion on this, I have added a TODO item:

* Add NUMERIC division operator that doesn't round?

  Currently NUMERIC _rounds_ the result to the specified precision.
  This means division can return a result that multiplied by the
  divisor is greater than the dividend, e.g. this returns a value  10:

SELECT (10::numeric(2,0) / 6::numeric(2,0))::numeric(2,0) * 6;

  The positive modulus result returned by NUMERICs might be considered
  inaccurate, in one sense.


---

Bruce Momjian wrote:
 
 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 [EMAIL PROTECTED] 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 1000::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 1000::numeric(30,6) /
 11::numeric(24,0);
?column?
 ---
  9090909090909090909090.909091
 (1 row)
  
  but there really is no _right_ value to prevent rounding (think
  0.999).  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.outMon Jun  6 21:01:11 2005
  ***
  *** 10,16 
SELECT avg(a) AS avg_32 FROM aggtest WHERE a  100;
   avg_32
-
  !  32.6667
(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.
(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 

Re: [HACKERS] [COMMITTERS] pgsql: Fix NUMERIC modulus to properly

2005-06-24 Thread Bruce Momjian

I don't think we can justify having NUMERIC division default to
truncation, especially since most division has non-zero decimal digits.

---

Paul Tillotson wrote:
 Bruce Momjian wrote:
 
 Tom Lane wrote:
   
 
 Christopher Kings-Lynne [EMAIL PROTECTED] 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 1000::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 1000::numeric(30,6) /
  11::numeric(24,0);
 ?column?
  ---
   9090909090909090909090.909091
  (1 row)
 
 but there really is no _right_ value to prevent rounding (think
 0.999).  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.6667
   (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.
   (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   

Re: [HACKERS] [COMMITTERS] pgsql: Fix NUMERIC modulus to properly truncate

2005-06-14 Thread Bruce Momjian

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 [EMAIL PROTECTED] 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 1000::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 1000::numeric(30,6) /
  11::numeric(24,0);
 ?column?
  ---
   9090909090909090909090.909091
  (1 row)
 
 but there really is no _right_ value to prevent rounding (think
 0.999).  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.6667
   (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.
   (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

Re: [HACKERS] [COMMITTERS] pgsql: Fix NUMERIC modulus to properly truncate

2005-06-06 Thread Bruce Momjian
Tom Lane wrote:
 Christopher Kings-Lynne [EMAIL PROTECTED] 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 1000::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 1000::numeric(30,6) /
11::numeric(24,0);
   ?column?
---
 9090909090909090909090.909091
(1 row)

but there really is no _right_ value to prevent rounding (think
0.999).  A non-rounding NUMERIC division would require duplicating
numeric_div() but with a false for 'round', and adding operators.

-- 
  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, Pennsylvania 19073

---(end of broadcast)---
TIP 4: Don't 'kill -9' the postmaster


Re: [HACKERS] [COMMITTERS] pgsql: Fix NUMERIC modulus to properly

2005-06-06 Thread Paul Tillotson

Bruce Momjian wrote:


Tom Lane wrote:
 


Christopher Kings-Lynne [EMAIL PROTECTED] 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 1000::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 1000::numeric(30,6) /
11::numeric(24,0);
   ?column?
---
 9090909090909090909090.909091
(1 row)

but there really is no _right_ value to prevent rounding (think
0.999).  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.outMon Jun  6 21:01:11 2005
***
*** 10,16 
  SELECT avg(a) AS avg_32 FROM aggtest WHERE a  100;
 avg_32
  -
!  32.6667
  (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.
  (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