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.
Created attachment 17887 [details] testcase (c++) This is the test code. I am hitting the "wrong ordering 2" code.
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)
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
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.
*** This bug has been marked as a duplicate of 323 ***
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.
The case (a < b) && (b < a) shows that not discarding the extra precision before performing a comparison leads to serious problems.
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.