Обсуждение: BUG in postgres mathematic
Postgres-7.0.3-2 RedHat-6.2 SELECT int8(5*27.81*100); 13904 SELECT int4(5*27.81*100); 13905 SELECT int8(27.81*100*5); 13905 -- ó Õ×ÁÖÅÎÉÅÍ, ÷ÁÝÅÎËÏ íÁËÓÉÍ, îÉÖÅÇÏÒÏÄÓËÉÅ ÉÎÆÏÒÍÁÃÉÏÎÎÙÅ ÓÅÔÉ (8312) 30-19-05, 34-00-02, 30-09-73 With best regards, Max Vaschenko, Nizhny Novgorod Information Networks.
This problem is not specific to Postgres. If you play around with a little C
program like:
#include <stdio.h>
int main(int argc, char * argv[])
{
float f = 27.81;
int i = 5;
int l = 100;
int ii = i*f*l;
long ll = l*f*i;
float ff = i*f*l;
printf("%i\n", ii);
printf("%li\n", ll);
printf("%.5f\n", ff);
printf("%i\n", (int) ff);
}
It prints:
13904
13904
13905.00000
13905
There is probably a good explanation for this. gcc 2.95 and egcs 2.91.66 do
this. Maybe a rounding problem.
On Thursday 25 January 2001 05:34, Max Vaschenko wrote:
> Postgres-7.0.3-2
> RedHat-6.2
>
> SELECT int8(5*27.81*100);
> 13904
>
> SELECT int4(5*27.81*100);
> 13905
>
> SELECT int8(27.81*100*5);
> 13905
--
-------- Robert B. Easter reaster@comptechnews.com ---------
-- CompTechNews Message Board http://www.comptechnews.com/ --
-- CompTechServ Tech Services http://www.comptechserv.com/ --
---------- http://www.comptechnews.com/~reaster/ ------------
"Robert B. Easter" <reaster@comptechnews.com> writes:
> This problem is not specific to Postgres.
The fact that 5*27.81*100 != 27.81*100*5 is certainly a garden-variety
floating-point roundoff error. However, I think Max has a fair
complaint here: it seems float-to-int8 conversion is truncating, not
rounding like the other conversions to integer do.
regression=# select 4.7::float8::int4;
?column?
----------
5
(1 row)
regression=# select 4.7::float8::int8;
?column?
----------
4
(1 row)
Seems to me this is a bug we should fix.
regards, tom lane
On Thursday 25 January 2001 22:52, Tom Lane wrote: > "Robert B. Easter" <reaster@comptechnews.com> writes: > > This problem is not specific to Postgres. > > The fact that 5*27.81*100 != 27.81*100*5 is certainly a garden-variety > floating-point roundoff error. However, I think Max has a fair > complaint here: it seems float-to-int8 conversion is truncating, not > rounding like the other conversions to integer do. > > regression=# select 4.7::float8::int4; > ?column? > ---------- > 5 > (1 row) > > regression=# select 4.7::float8::int8; > ?column? > ---------- > 4 > (1 row) > > Seems to me this is a bug we should fix. > > regards, tom lane Yeah, I agree. It isn't right that it truncates and that is something C does appearently. The fix is to pass the float through a rounding something like (long)(f + 0.5) or else C just truncates it off. This must already be happening for the int4 conversion or C would do the same thing to it. I didn't look at the Postgres sources yet, but it is probably one of those very easy things to fix. :) -- -------- Robert B. Easter reaster@comptechnews.com --------- -- CompTechNews Message Board http://www.comptechnews.com/ -- -- CompTechServ Tech Services http://www.comptechserv.com/ -- ---------- http://www.comptechnews.com/~reaster/ ------------
Notice how the INT4 rounding is banker's rounding (round to the nearest even
number). That is what we would want the INT8 to do as well, not just a
simple round like I mentioned before. Again, the INT8 shows truncation. I've
been looking around the source code, but I can't see where all this
happens.
reaster=# SELECT 1.5::FLOAT::INT4;
?column?
----------
2
(1 row)
reaster=# SELECT 2.5::FLOAT::INT4;
?column?
----------
2
(1 row)
reaster=# SELECT 1.5::FLOAT::INT8;
?column?
----------
1
(1 row)
reaster=# SELECT 2.5::FLOAT::INT8;
?column?
----------
2
(1 row)
On Thursday 25 January 2001 22:52, Tom Lane wrote:
> "Robert B. Easter" <reaster@comptechnews.com> writes:
> > This problem is not specific to Postgres.
>
> The fact that 5*27.81*100 != 27.81*100*5 is certainly a garden-variety
> floating-point roundoff error. However, I think Max has a fair
> complaint here: it seems float-to-int8 conversion is truncating, not
> rounding like the other conversions to integer do.
>
> regression=# select 4.7::float8::int4;
> ?column?
> ----------
> 5
> (1 row)
>
> regression=# select 4.7::float8::int8;
> ?column?
> ----------
> 4
> (1 row)
>
> Seems to me this is a bug we should fix.
>
> regards, tom lane
--
-------- Robert B. Easter reaster@comptechnews.com ---------
-- CompTechNews Message Board http://www.comptechnews.com/ --
-- CompTechServ Tech Services http://www.comptechserv.com/ --
---------- http://www.comptechnews.com/~reaster/ ------------
>> The fact that 5*27.81*100 != 27.81*100*5 is certainly a garden-variety
>> floating-point roundoff error. However, I think Max has a fair
>> complaint here: it seems float-to-int8 conversion is truncating, not
>> rounding like the other conversions to integer do.
I have changed float8-to-int8 to start with an rint() call, the same as
float8-to-int4 and float8-to-int2. This should give the same roundoff
behavior as the other cases, including round-to-nearest-even if your
hardware supports IEEE-compliant float math.
Curiously, this change exposed what I take to be a platform dependency
in the int8 regress test. It was computing
int8(float8(4567890123456789::int8)) and expecting to get back exactly
4567890123456789. However, that value is 53 bits long and so there is
no margin for error in a standard IEEE float8 value. I find that at
least on HP hardware, rint() treats the value as inexact and rounds to
nearest even:
regression=# select round(4567890123456788::float8) - 4567890123456780::float8;
?column?
----------
8
(1 row)
regression=# select round(4567890123456789::float8) - 4567890123456780::float8;
?column?
----------
8
(1 row)
regression=# select round(4567890123456790::float8) - 4567890123456780::float8;
?column?
----------
10
(1 row)
regression=#
Whether this is a bug in rint or spec-compliant behavior is unclear, but
I'll bet HP's hardware is not the only platform that behaves this way.
Since I'm not eager to try to develop a new set of platform-specific
int8 expected files at this late hour, I just diked out that test
instead...
regards, tom lane
On Friday 26 January 2001 18:07, Tom Lane wrote:
> Curiously, this change exposed what I take to be a platform dependency
> in the int8 regress test. It was computing
> int8(float8(4567890123456789::int8)) and expecting to get back exactly
> 4567890123456789. However, that value is 53 bits long and so there is
> no margin for error in a standard IEEE float8 value. I find that at
> least on HP hardware, rint() treats the value as inexact and rounds to
> nearest even:
>
> regression=# select round(4567890123456788::float8) -
> 4567890123456780::float8; ?column?
> ----------
> 8
> (1 row)
>
> regression=# select round(4567890123456789::float8) -
> 4567890123456780::float8; ?column?
> ----------
> 8
> (1 row)
>
> regression=# select round(4567890123456790::float8) -
> 4567890123456780::float8; ?column?
> ----------
> 10
> (1 row)
>
> regression=#
>
> Whether this is a bug in rint or spec-compliant behavior is unclear, but
> I'll bet HP's hardware is not the only platform that behaves this way.
> Since I'm not eager to try to develop a new set of platform-specific
> int8 expected files at this late hour, I just diked out that test
> instead...
Here is what I get on Linux (PIII):
reaster=# select round(4567890123456788::float8) - 4567890123456780::float8;
?column?
----------
8
(1 row)
reaster=# select round(4567890123456789::float8) - 4567890123456780::float8;
?column?
----------
9
(1 row)
reaster=# select round(4567890123456790::float8) - 4567890123456780::float8;
?column?
----------
10
(1 row)
I'm not sure what the problem is either. The PIII has an 80-bit FPU but not
sure that matters. When there is no exponent, maybe only 52 bits are really
in the mantissa. If you try rounding numbers <= 4503599627370495 (2^52 - 1),
maybe you'll get expected results. The hidden bit is 0. Could be that round
or rint (whatever it is) always makes the hidden bit 1 when I think it should
only be 1 when the exponent is nonzero. I'm no float expert! :) Feel free
to correct me.
--
-------- Robert B. Easter reaster@comptechnews.com ---------
-- CompTechNews Message Board http://www.comptechnews.com/ --
-- CompTechServ Tech Services http://www.comptechserv.com/ --
---------- http://www.comptechnews.com/~reaster/ ------------