Gcc floating-point optimizer weird behaviour

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hello.

I've found a strange behaviour of gcc (4.8.5-20150122) optimizer
relating floating-point on x86 (32 bit).

I have two files (a.c and f.c, look below). In a.c:main() there are two
variables, d and e, assigned the same function call result. But the
optimizer causes their values to be different.

I understand that all floating-point operations are actually calculated
by the processor using long double type then casting the result to the
target type (double in our case). But in our case both variables are of
type double and the same casting should happen which would lead to the
equal values.

Is it gcc bug or do I misunderstand how floating-point arithmetics
works in C and what is allowed for optimizer?

If it's my fault can anyone explain (e.g. provide links) please why
it's an allowed behaviour of optimizer?

I met the similar issue in spead-dreams-2 2.1.0 (in SOLID-2.0 library)
where it makes playing almost impossible leading to game hangs after
10-60 seconds of playing.

Roughly speaking, in SOLID-2.0 code the issue causes a function to
think that in an array every value is greater than the next one and the
last value is greater than the first one (which is obviously not
possible). (I can provide the details if necessary).

How to reproduce the issue:
$ cat >a.c <<EOF
#include <stdio.h>

#define A 0.0026963419787128717
#define B 820.72515869140625
#define C 0.02293671065653248
#define D 398.6868896484375

double f (double a, double b, double c, double d);

double g (double a, double b, double c, double d)
{ return a*b + c*d; }

int main () {
        double d = f(A, B, C, D), e = f(A, B, C, D);
        int d_gt_e = d > e, d_lt_e = d < e;
        printf("d>e=%d d<e=%d\n%.40lf\n%.40lf\n", d_gt_e, d_lt_e, d, e);
        return 0;
}
EOF
$ cat >f.c <<EOF
double g (double a, double b, double c, double d);

double f (double a, double b, double c, double d)
{ return g(a, b, c, d); }
EOF
$ cc -O1 a.c f.c
$ ./a.out
d>e=1 d<e=0
11.3575215287845274758637970080599188804626
11.3575215287845274758637970080599188804626

$ cc -v
Using built-in specs.
COLLECT_GCC=cc
COLLECT_LTO_WRAPPER=/usr/lbin/gcc/i686-pc-linux-gnu/4.8.5/lto-wrapper
Target: i686-pc-linux-gnu
Configured with: ../gcc-4.8-20131128/configure --target=i686-pc-linux-gnu --prefix=/usr --libexecdir=/usr/lbin --with-native-system-header-dir=/usr/include --with-gxx-include-dir=/usr/include/c++/4.8.5 --enable-languages=c,c++,objc,obj-c++ --with-linker-hash-style=gnu --enable-shared --enable-threads=posix --enable-__cxa_atexit --enable-clocale=gnu --enable-objc-gc --disable-checking --disable-nls --with-system-zlib
Thread model: posix
gcc version 4.8.5 20150122 (prerelease) (GCC) 

Actual output:
d>e=1 d<e=0

Expected output:
d>e=0 d<e=0

Or expected output (it's still incorrect but I would understand it;
what I don't understand is why the comparison results are different):
d>e=1 d<e=1

--
Vladimir A. Pavlov





[Index of Archives]     [Linux C Programming]     [Linux Kernel]     [eCos]     [Fedora Development]     [Fedora Announce]     [Autoconf]     [The DWARVES Debugging Tools]     [Yosemite Campsites]     [Yosemite News]     [Linux GCC]

  Powered by Linux