The 85/0.0085 mistery ?

Started by Jean-Christophe Pazzagliaover 25 years ago7 messages
#1Jean-Christophe Pazzaglia
jc.pazzaglia@albourne.com

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)

#2Frederick W. Reimer
fwr@ga.prestige.net
In reply to: Jean-Christophe Pazzaglia (#1)
RE: The 85/0.0085 mistery ?

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

Show quoted text

-----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)

#3Jean-Christophe Pazzaglia
jc.pazzaglia@albourne.com
In reply to: Frederick W. Reimer (#2)
Re: The 85/0.0085 mistery ?

"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

#4Hannu Krosing
hannu@tm.ee
In reply to: Frederick W. Reimer (#2)
Re: The 85/0.0085 mistery ?

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.0000
81 | 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

#5Hannu Krosing
hannu@tm.ee
In reply to: Frederick W. Reimer (#2)
Re: The 85/0.0085 mistery ?

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

#6Tom Lane
tgl@sss.pgh.pa.us
In reply to: Frederick W. Reimer (#2)
Re: The 85/0.0085 mistery ?

"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

#7Tom Lane
tgl@sss.pgh.pa.us
In reply to: Hannu Krosing (#4)
Re: The 85/0.0085 mistery ?

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