[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