[prev in list] [next in list] [prev in thread] [next in thread]
List: gcc-bugs
Subject: problem with double numbers
From: Cedric Roux <Cedric.Roux () lip6 ! fr>
Date: 2001-10-31 17:05:33
[Download RAW message or body]
Here we go :
/users/cao/cedric/c/d>uname -m
i686
(it's a pentium III)
/users/cao/cedric/c/d>cat d.c
#include <stdio.h>
#include <math.h>
long t=10;
int main(void)
{
double x = 0.6;
long y = 10;
printf("x (local var, double) = %g\n", x);
printf("y (local var, long) = %ld\n", y);
printf("t (global var, long) = %ld\n", t);
printf("and we compute x * y and x * t :\n");
printf("ceil: %ld %ld\n", (long)ceil(x * y), (long)ceil(x * t));
printf("floor: %ld %ld\n", (long)floor(x * y), (long)floor(x * t));
printf("rint: %ld %ld\n", (long)rint(x * y), (long)rint(x * t));
printf("none: %ld %ld\n", (long)(x * y), (long)(x * t));
return 0;
}
/users/cao/cedric/c/d>gcc -v
Reading specs from /usr/lib/gcc-lib/i386-redhat-linux/2.96/specs
gcc version 2.96 20000731 (Red Hat Linux 7.1 2.96-85)
(got the same problem with a egcs version on another host,
no gcc 3 available, sorry)
/users/cao/cedric/c/d>gcc -o d d.c -Wall -lm
(this is not a libm problem, the ceil, floor and rint stuff are included
for informationnal purpose only, this is not a printf problem either)
/users/cao/cedric/c/d>./d
x (local var, double) = 0.6
y (local var, long) = 10
t (global var, long) = 10
and we compute x * y and x * t :
ceil: 6 6
floor: 6 6
rint: 6 6
none: 5 5
(ceil = floor = 6 => none should be 6, no ? and now the funniest)
/users/cao/cedric/c/d>gcc -o d d.c -Wall -lm -O2
/users/cao/cedric/c/d>./d
x (local var, double) = 0.6
y (local var, long) = 10
t (global var, long) = 10
and we compute x * y and x * t :
ceil: 6 6
floor: 6 5
rint: 6 6
none: 6 5
(we've got y = t but x * y != x * t, if I remember my math lessons,
if a = b then a * c = b * c (with a, b and c real numbers))
The same on a sparc with gcc gives 6 for all results with and without -O2.
Some ideas :
the difference between -O2 and no optimization is due to the
precalculation done within the compiler (it pushes 6 on the stack
then calls printf for the local/local multiplication, so that explains the
diffences seen in -O2 for the same mode).
Why do we get 5 and not 6 as expected ?
0.6 can't be represented as a base2 _finite_ number
(0.6 * 2 = 1.2, 1.2 * 2 = 2.4, 2.4 * 2 = 4.8, 4.8 * 2 = 9.6 and we
come back with a .6 stuff, looping on .6 .2 .4 .8)
By inspecting the ia32 code produced, we see (for the rounding of the
double to the long, after the mul) :
fnstcw -16(%ebp)
movl -16(%ebp), %edx
movb $12, -15(%ebp)
fldcw -16(%ebp)
which (by reading intel documentation) means :
setting the fpu control word up byte to the $12 value.
10#12 = 2#1100
precision control = 0 => single precision
rounding control = 3 => round toward zero (truncate) : rounded result is
closest to but no greater in absolute value than the infinitely precise
result.
infinity control = 0 (we don't care here)
So the problem could be the rounding mode or the precision mode, or both.
With float we get :
ceil: 7 7
floor: 6 6
rint: 6 6
none: 6 6
without -O2 and :
ceil: 6 7
floor: 6 6
rint: 6 6
none: 6 6
with -O2
(the same stands for 6 and 7 difference, precalculation done by compiler)
With long double we get :
ceil: 6 6
floor: 6 6
rint: 6 6
none: 5 5
without -O2
and :
ceil: 6 6
floor: 6 6
rint: 6 6
none: 5 5
with
(by watching asm code, seems to use mode 3 for rounding too (with none))
So my questions are :
is it a gcc bug (or is it natural behavior of a C compiler with ia32,
maybe the ieeeXXX says it should behave this way, but if yes, why
differences between ia32 and sparc ? maybe they don't respect the same
ieeeXXX...) ? If yes, where does it come from ?
and please, could you solve this ?
Best regards,
Cedric.
Vincent must be blamed for this if there is no bug at all,
because the wrong result came from his code :))))))
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic