Обсуждение: The 85/0.0085 mistery ?

Поиск
Список
Период
Сортировка

The 85/0.0085 mistery ?

От
Jean-Christophe Pazzaglia
Дата:
Hi,


Well, I discovered a strange behavior (ie 85/0.0085 <> 10000 )
Is my SQL wrong or  is it postgres ?
We are running 7.02 (but also 6.x) on a alpha (alphaev6) box.


Thanks in advance.

jc

Here is a snapshot 

jctest=> create table eigthyfive ( cs float4, csbytenthousand float4,
csbyhundred float);
CREATE  

jctest=> insert into eigthyfive VALUES (88,0.0088,0.88);
INSERT 7973003 1
jctest=> insert into eigthyfive VALUES (86,0.0086,0.86);
INSERT 7973004 1
jctest=> insert into eigthyfive VALUES (85,0.0085,0.85);
INSERT 7973005 1
jctest=>  insert into eigthyfive VALUES (84,0.0084,0.84);
INSERT 7973006 1

jctest=> select * from eigthyfive ;cs | csbytenthousand | csbyhundred
----+-----------------+-------------88 |          0.0088 |        0.8886 |          0.0086 |        0.8685 |
0.0085|        0.8584 |          0.0084 |        0.84
 
(4 rows)
jctest=> select * from eigthyfive where (cs/csbytenthousand=10000);cs | csbytenthousand | csbyhundred
----+-----------------+-------------88 |          0.0088 |        0.8886 |          0.0086 |        0.8684 |
0.0084|        0.84
 
(3 rows)
*** oh oh 85 disappeared ! ***

BUT

jctest=> select (85/0.0085=10000);?column?
----------t
(1 row)


jctest=> select * from eigthyfive where (cs/csbyhundred=100);cs | csbytenthousand | csbyhundred
----+-----------------+-------------88 |          0.0088 |        0.8886 |          0.0086 |        0.8685 |
0.0085|        0.8584 |          0.0084 |        0.84
 
(4 rows)

** 85 is back ** 

jctest=> insert into eigthyfive VALUES (85,0.00085);
INSERT 7973007 1
jctest=> select * from eigthyfive where (cs/csbytenthousand=100000);cs | csbytenthousand | csbyhundred
----+-----------------+-------------85 |         0.00085 |
(1 row)

RE: The 85/0.0085 mistery ?

От
"Frederick W. Reimer"
Дата:
Nothing is wrong, that's just how computers work.  Fractional numbers are
stored in a variety of formats on different platforms.  Most support the
IEEE formats, but some use their own formats.  In all cases, that I'm aware
of, the numbers are stored as a mantissa and exponent.  The numbers are
"base 2", so certain base 10 numbers don't have an exact representation in
base 2, no matter how many bits are used in the mantissa.  Other base 10
numbers have problems with the "short" mantissa formats, but are represented
exactly with the "long" mantissa formats.

In general, it's recommended you don't check for exact equivalence when
doing calculations on real numbers and instead check for "almost exactness."
In other words, depending on the format used on your machine, 85/0.0085 may
be equal to 1000.000000000000001.

Of course, this may all be wrong, but that's my understanding.  I think they
mention this in the docs for the regression tests.  Check them out!

Fred Reimer
Eclipsys Corporation



> -----Original Message-----
> From: pgsql-hackers-owner@hub.org
> [mailto:pgsql-hackers-owner@hub.org]On
> Behalf Of Jean-Christophe Pazzaglia
> Sent: Friday, October 06, 2000 8:28 AM
> To: PostgreSQL-development
> Subject: [HACKERS] The 85/0.0085 mistery ?
>
>
> Hi,
>
>
> Well, I discovered a strange behavior (ie 85/0.0085 <> 10000 )
> Is my SQL wrong or  is it postgres ?
> We are running 7.02 (but also 6.x) on a alpha (alphaev6) box.
>
>
> Thanks in advance.
>
> jc
>
> Here is a snapshot
>
> jctest=> create table eigthyfive ( cs float4, csbytenthousand float4,
> csbyhundred float);
> CREATE
>
> jctest=> insert into eigthyfive VALUES (88,0.0088,0.88);
> INSERT 7973003 1
> jctest=> insert into eigthyfive VALUES (86,0.0086,0.86);
> INSERT 7973004 1
> jctest=> insert into eigthyfive VALUES (85,0.0085,0.85);
> INSERT 7973005 1
> jctest=>  insert into eigthyfive VALUES (84,0.0084,0.84);
> INSERT 7973006 1
>
> jctest=> select * from eigthyfive ;
>  cs | csbytenthousand | csbyhundred
> ----+-----------------+-------------
>  88 |          0.0088 |        0.88
>  86 |          0.0086 |        0.86
>  85 |          0.0085 |        0.85
>  84 |          0.0084 |        0.84
> (4 rows)
>
>  jctest=> select * from eigthyfive where (cs/csbytenthousand=10000);
>  cs | csbytenthousand | csbyhundred
> ----+-----------------+-------------
>  88 |          0.0088 |        0.88
>  86 |          0.0086 |        0.86
>  84 |          0.0084 |        0.84
> (3 rows)
>
> *** oh oh 85 disappeared ! ***
>
> BUT
>
> jctest=> select (85/0.0085=10000);
>  ?column?
> ----------
>  t
> (1 row)
>
>
> jctest=> select * from eigthyfive where (cs/csbyhundred=100);
>  cs | csbytenthousand | csbyhundred
> ----+-----------------+-------------
>  88 |          0.0088 |        0.88
>  86 |          0.0086 |        0.86
>  85 |          0.0085 |        0.85
>  84 |          0.0084 |        0.84
> (4 rows)
>
> ** 85 is back **
>
> jctest=> insert into eigthyfive VALUES (85,0.00085);
> INSERT 7973007 1
> jctest=> select * from eigthyfive where (cs/csbytenthousand=100000);
>  cs | csbytenthousand | csbyhundred
> ----+-----------------+-------------
>  85 |         0.00085 |
> (1 row)



Re: The 85/0.0085 mistery ?

От
Jean-Christophe Pazzaglia
Дата:
"Frederick W. Reimer" wrote:
>
> Nothing is wrong, that's just how computers work.  Fractional numbers are
> stored in a variety of formats on different platforms.  Most support the
> IEEE formats, but some use their own formats.  In all cases, that I'm aware
> of, the numbers are stored as a mantissa and exponent.  The numbers are
> "base 2", so certain base 10 numbers don't have an exact representation in
> base 2, no matter how many bits are used in the mantissa.  Other base 10
> numbers have problems with the "short" mantissa formats, but are represented
> exactly with the "long" mantissa formats.

thank you for the lesson,
I probably have done too much database this time :o

what I was really affraid was the BUT clause ...

> >  jctest=> select * from eigthyfive where (cs/csbytenthousand=10000);
> >  cs | csbytenthousand | csbyhundred
> > ----+-----------------+-------------
> >  88 |          0.0088 |        0.88
> >  86 |          0.0086 |        0.86
> >  84 |          0.0084 |        0.84
> > (3 rows)
> >
> > *** oh oh 85 disappeared ! ***
> >
> > BUT
> >
> > jctest=> select (85/0.0085=10000);
> >  ?column?
> > ----------
> >  t
> > (1 row)

... It seems that this is due to the single precision
(float4) instead of double precision (float)
(and even with a test done in base 3 :P)
BTW there is no round(float4) function

thanks

jc
Вложения

Re: The 85/0.0085 mistery ?

От
Tom Lane
Дата:
"Frederick W. Reimer" <fwr@ga.prestige.net> writes:
> In general, it's recommended you don't check for exact equivalence when
> doing calculations on real numbers and instead check for "almost exactness."

Or use datatype NUMERIC, which behaves in a more intuitive way (at least
for people who are accustomed to thinking in decimal).  But yes, exact
equality checks on float values are usually foolish.
        regards, tom lane


Re: The 85/0.0085 mistery ?

От
Hannu Krosing
Дата:
Tom Lane wrote:
> 
> "Frederick W. Reimer" <fwr@ga.prestige.net> writes:
> > In general, it's recommended you don't check for exact equivalence when
> > doing calculations on real numbers and instead check for "almost exactness."
> 


perhaps "where trunc(85/0.0085) = 10000" works better.


> Or use datatype NUMERIC, which behaves in a more intuitive way (at least
> for people who are accustomed to thinking in decimal).  But yes, exact
> equality checks on float values are usually foolish.

But ...

hannu=# create table ntest(n numeric(3), n1 numeric(6,4));
CREATE
hannu=# insert into ntest values(80, 80/10000);
INSERT 311338 1
hannu=# insert into ntest values(81, 81/10000);
INSERT 311339 1
hannu=# select count(*) from ntest where n/n1 = 10000;
ERROR:  division by zero on numeric
hannu=# select * from ntest;n  |   n1   
----+--------80 | 0.000081 | 0.0000

eek !

I understand why this is so, but should it be ?

Can't we assume that 80/10000 is numeric and back-propagate that 
knowledge to constituents so that 80 and 10000 are also considered 
numetics. 

Or even better assume that 80/10000 is a rational number ;)

-------------------
Hannu


Re: The 85/0.0085 mistery ?

От
Hannu Krosing
Дата:
Hannu Krosing wrote:
> 
> Tom Lane wrote:
> >
> > "Frederick W. Reimer" <fwr@ga.prestige.net> writes:
> > > In general, it's recommended you don't check for exact equivalence when
> > > doing calculations on real numbers and instead check for "almost exactness."
> >
> 
> perhaps "where trunc(85/0.0085) = 10000" works better.

ok I tested it and it does not work ;(

hannu=# select trunc(85.0::float4/0.0085::float4) = '10000';
ERROR:  Function 'trunc(float4)' does not exist       Unable to identify a function that satisfies the given argument
types      You may need to add explicit typecasts
 
hannu=# select trunc(float8(85.0::float4/0.0085::float4));trunc 
------- 9999
(1 row)

But this does work 

hannu=# select text(85.0::float4/0.0085::float4) = '10000';?column? 
----------t
(1 row)
As does this

hannu=# select round(float8(85.0::float4/0.0085::float4));round 
-------10000
(1 row)

--------------
Hannu


Re: The 85/0.0085 mistery ?

От
Tom Lane
Дата:
Hannu Krosing <hannu@tm.ee> writes:
> Can't we assume that 80/10000 is numeric

I don't think so, unless you want to break a lot of existing
applications that assume integer/integer means integer division.
        regards, tom lane