Bug 40186

Summary: floating point comparison is wrong ( !(a < b) && (b > a) is true )
Product: gcc Reporter: Albert Zeyer <ich>
Component: c++Assignee: Not yet assigned to anyone <unassigned>
Status: RESOLVED DUPLICATE    
Severity: normal CC: 166255, 36876, adam, anoullez, benoit.sibaud, bernert, birger.b, brad_atcheson, brooks, cognot, csk, debian-gcc, denis.nagorny, deshpand, doko, dsell, dyang, eda-qa, fang, gbburkhardt, gcc-bugs, gcc-erikd, gcczilla1, Graham.Murphy, green, gsinai, gtalbot, have, hjl.tools, ich, ismail, jmurray, konstantin, lani, macracan, mbrudka, neff.kevin, nicos, nouiz, npr1, olcios, P.Schaffnit, paul_blankenbaker, pepalogik, petr.savicky, piaget, pr2345, preciseflight, purnnam1, roebel, rohit.x.tripathi, rozenman, sk2alexa, sliwa, sunjoong, themis_hv, tjf, tterribe, u.strempel, vincent-gcc, whaley, wirawan0, xiaoyi_wu, ywei
Priority: P3    
Version: unknown   
Target Milestone: ---   
Host: Gentoo Linux i386 Target: Linux i686
Build: tried with GCC 4.1.2, 4.3.2 and 4.4.0 Known to work:
Known to fail: Last reconfirmed:
Attachments: testcase (c++)
simpler test case (now for wrong ordering case 1)

Description Albert Zeyer 2009-05-18 13:08:40 UTC
When comparing the return value of two functions (which both return double and do always return the same value), I have the case that (a < b) && (b < a) (whereby they should be equal) in a real world application.

I tried to reproduce it, though in the test case, I have a slightly different case, which should be also wrong: !(a < b) && (b > a) is true (whereby it should be a == b).

Probably both problems are related.

The behaviour pretty much depend on the optimisation. With -O0 and -Os, I am hitting the problem, but not so with -O1, -O2 and -O3.
Comment 1 Albert Zeyer 2009-05-18 13:11:34 UTC
Created attachment 17887 [details]
testcase (c++)

This is the test code. I am hitting the "wrong ordering 2" code.
Comment 2 Albert Zeyer 2009-05-18 13:16:10 UTC
This is a real problem, because in my real application, I tried to use a very similar order in a std::set<tmp*,CustomOrder>, defined like this:

struct CustomOrder {
	bool operator()(const Tmp* a, const Tmp* b) const {
		return a->get() < b->get();
	}
};

STLport gives this assertion when inserting Tmp pointers with equal values (returned by get() function):

/usr/include/stlport/stl/debug/_tree.h(63): STL error : Invalid strict weak ordering predicate, if pred(a, b) then we should have !pred(b, a)
/usr/include/stlport/stl/debug/_tree.h(63): STL assertion failure:     !_M_non_dbg_cmp(__rhs, __lhs) 
Comment 3 Albert Zeyer 2009-05-18 13:17:38 UTC
Some compiler information:

az@acompneu ~/Programmierung $ g++ -Os -v -ggdb test_order.cpp -o test_order && ./test_order
Using built-in specs.
Target: i686-pc-linux-gnu
Configured with: /var/tmp/portage/sys-devel/gcc-4.4.0/work/gcc-4.4.0/configure --prefix=/usr --bindir=/usr/i686-pc-linux-gnu/gcc-bin/4.4.0 --includedir=/usr/lib/gcc/i686-pc-linux-gnu/4.4.0/include --datadir=/usr/share/gcc-data/i686-pc-linux-gnu/4.4.0 --mandir=/usr/share/gcc-data/i686-pc-linux-gnu/4.4.0/man --infodir=/usr/share/gcc-data/i686-pc-linux-gnu/4.4.0/info --with-gxx-include-dir=/usr/lib/gcc/i686-pc-linux-gnu/4.4.0/include/g++-v4 --host=i686-pc-linux-gnu --build=i686-pc-linux-gnu --disable-altivec --disable-fixed-point --with-ppl --with-cloog --enable-nls --without-included-gettext --with-system-zlib --disable-checking --disable-werror --enable-secureplt --disable-multilib --enable-libmudflap --disable-libssp --enable-libgomp --enable-cld --enable-java-awt=gtk --with-arch=i686 --enable-languages=c,c++,java,objc,fortran --enable-shared --enable-threads=posix --enable-__cxa_atexit --enable-clocale=gnu --with-bugurl=http://bugs.gentoo.org/ --with-pkgversion='Gentoo 4.4.0'
Thread model: posix
gcc version 4.4.0 (Gentoo 4.4.0) 
COLLECT_GCC_OPTIONS='-Os' '-v' '-ggdb' '-o' 'test_order' '-shared-libgcc' '-mtune=generic' '-march=i686'
 /usr/libexec/gcc/i686-pc-linux-gnu/4.4.0/cc1plus -quiet -v -D_GNU_SOURCE test_order.cpp -quiet -dumpbase test_order.cpp -mtune=generic -march=i686 -auxbase test_order -ggdb -Os -version -o /tmp/cc2REzjQ.s
ignoring nonexistent directory "/usr/lib/gcc/i686-pc-linux-gnu/4.4.0/../../../../i686-pc-linux-gnu/include"
#include "..." search starts here:
#include <...> search starts here:
 /usr/lib/gcc/i686-pc-linux-gnu/4.4.0/include/g++-v4
 /usr/lib/gcc/i686-pc-linux-gnu/4.4.0/include/g++-v4/i686-pc-linux-gnu
 /usr/lib/gcc/i686-pc-linux-gnu/4.4.0/include/g++-v4/backward
 /usr/local/include
 /usr/lib/gcc/i686-pc-linux-gnu/4.4.0/include
 /usr/lib/gcc/i686-pc-linux-gnu/4.4.0/include-fixed
 /usr/include
End of search list.
GNU C++ (Gentoo 4.4.0) version 4.4.0 (i686-pc-linux-gnu)
	compiled by GNU C version 4.4.0, GMP version 4.2.4, MPFR version 2.4.1-p1.
GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
Compiler executable checksum: 13a3af7fd37a02ca6104ed29e33fcca6
COLLECT_GCC_OPTIONS='-Os' '-v' '-ggdb' '-o' 'test_order' '-shared-libgcc' '-mtune=generic' '-march=i686'
 /usr/lib/gcc/i686-pc-linux-gnu/4.4.0/../../../../i686-pc-linux-gnu/bin/as -V -Qy -o /tmp/cc5XznpU.o /tmp/cc2REzjQ.s
GNU assembler version 2.18 (i686-pc-linux-gnu) using BFD version (GNU Binutils) 2.18
COMPILER_PATH=/usr/libexec/gcc/i686-pc-linux-gnu/4.4.0/:/usr/libexec/gcc/i686-pc-linux-gnu/4.4.0/:/usr/libexec/gcc/i686-pc-linux-gnu/:/usr/lib/gcc/i686-pc-linux-gnu/4.4.0/:/usr/lib/gcc/i686-pc-linux-gnu/:/usr/libexec/gcc/i686-pc-linux-gnu/4.4.0/:/usr/libexec/gcc/i686-pc-linux-gnu/:/usr/lib/gcc/i686-pc-linux-gnu/4.4.0/:/usr/lib/gcc/i686-pc-linux-gnu/:/usr/lib/gcc/i686-pc-linux-gnu/4.4.0/../../../../i686-pc-linux-gnu/bin/
LIBRARY_PATH=/usr/lib/gcc/i686-pc-linux-gnu/4.4.0/:/usr/lib/gcc/i686-pc-linux-gnu/4.4.0/:/usr/lib/gcc/i686-pc-linux-gnu/4.4.0/../../../../i686-pc-linux-gnu/lib/:/usr/lib/gcc/i686-pc-linux-gnu/4.4.0/../../../:/lib/:/usr/lib/
COLLECT_GCC_OPTIONS='-Os' '-v' '-ggdb' '-o' 'test_order' '-shared-libgcc' '-mtune=generic' '-march=i686'
 /usr/libexec/gcc/i686-pc-linux-gnu/4.4.0/collect2 --eh-frame-hdr -m elf_i386 -dynamic-linker /lib/ld-linux.so.2 -o test_order /usr/lib/gcc/i686-pc-linux-gnu/4.4.0/../../../crt1.o /usr/lib/gcc/i686-pc-linux-gnu/4.4.0/../../../crti.o /usr/lib/gcc/i686-pc-linux-gnu/4.4.0/crtbegin.o -L/usr/lib/gcc/i686-pc-linux-gnu/4.4.0 -L/usr/lib/gcc/i686-pc-linux-gnu/4.4.0 -L/usr/lib/gcc/i686-pc-linux-gnu/4.4.0/../../../../i686-pc-linux-gnu/lib -L/usr/lib/gcc/i686-pc-linux-gnu/4.4.0/../../.. /tmp/cc5XznpU.o -lstdc++ -lm -lgcc_s -lgcc -lc -lgcc_s -lgcc /usr/lib/gcc/i686-pc-linux-gnu/4.4.0/crtend.o /usr/lib/gcc/i686-pc-linux-gnu/4.4.0/../../../crtn.o
wrong ordering 2! 993.747, 993.747
d = 990.91854039579629898
v1 = 1600861594,1600861595
v2 = 1600861596,1600861593
8 chars: 3c7f1bcaf90d8f40
d = 990.91854039579629898
v1 = 5f6b359a,5f6b359b
v2 = 5f6b359c,5f6b3599
8 chars: 3c7f1bcaf90d8f40
Comment 4 Albert Zeyer 2009-05-18 13:38:36 UTC
Created attachment 17888 [details]
simpler test case (now for wrong ordering case 1)

I was able to reproduce the first case now ("wrong ordering 1"). I also removed some parts from the test case, it's much shorter now.

This occurs only with -Os now, in all other cases, I don't hit the problem.
Comment 5 Andrew Pinski 2009-05-18 14:11:44 UTC

*** This bug has been marked as a duplicate of 323 ***
Comment 6 Andrew Pinski 2009-05-18 14:49:07 UTC
Either use -ffloat-store or -mfpmath=sse .  The issue comes from excessive precision.  It is not < or > which is causing the problem but keeping one of a or b in the fp stack register but putting the other one on the normal memory.
Comment 7 sliwa@cft.edu.pl 2009-05-18 14:52:43 UTC
The case (a < b) && (b < a) shows that not discarding the extra precision before performing a comparison leads to serious problems.
Comment 8 Vincent Lefèvre 2009-05-18 14:56:29 UTC
Are you sure that this comes from the extended precision? This would mean that GCC does implicit extended -> double conversions in an asymmetric way, and IIRC, I've never seen that.

I can't reproduce the problem with g++-4.4 -mfpmath=387 -Os on an x86_64 machine.