Created attachment 57491 [details] The test application In GCC version 13 and later, we've found some inconsistency in the way the compiler calculates double constants in our code. We originally discovered this in a rounding unit test in our code, and have extracted the specific inconsistency in attached double-test.cpp. When compiling in default 64-bit mode on the x86 platform, we get the consistent result of previous GCC versions (the output from the test code is the same constant double value calculated in three different ways, and dumped as hex as well): g++ -std=c++23 -m64 -o double-test double-test.cpp ./double-test Output: GCC version: 13.2.0 a = -5.42101e-20 ( 00 00 00 00 00 00 f0 bb ) b = -5.42101e-20 ( 00 00 00 00 00 00 f0 bb ) c = -5.42101e-20 ( 00 00 00 00 00 00 f0 bb ) However, compiling the same application in 32-bit mode yields a different result: g++ -std=c++23 -m32 -o double-test double-test.cpp ./double-test Output: GCC version: 13.2.0 a = -4.06576e-20 ( 00 00 00 00 00 00 e8 bb ) b = 0 ( 00 00 00 00 00 00 00 00 ) c = -4.06576e-20 ( 00 00 00 00 00 00 e8 bb ) If using gnu extensions as the selected standard, we're back to the old, consistent behavior, also for 32 bits: g++ -std=gnu++23 -m32 -o double-test double-test.cpp ./double-test Output: GCC version: 13.2.0 a = -5.42101e-20 ( 00 00 00 00 00 00 f0 bb ) b = -5.42101e-20 ( 00 00 00 00 00 00 f0 bb ) c = -5.42101e-20 ( 00 00 00 00 00 00 f0 bb ) We have only seen the problem in 32 bit mode with one of the strict c++ standards selected (-std=c++*), not with gnu extensions (-std=gnu++*). Testing various versions on the Compiler Explorer site, the problem seems to occur as of version 13 of GCC. g++ -v output: Using built-in specs. COLLECT_GCC=g++ COLLECT_LTO_WRAPPER=/usr/local/schilling/gcc-13.2.0/libexec/gcc/x86_64-pc-linux-gnu/13.2.0/lto-wrapper Target: x86_64-pc-linux-gnu Configured with: ../gcc-13.2.0/configure --prefix=/usr/local/schilling/gcc-13.2.0 --enable-shared --enable-threads=posix --enable-__cxa_atexit --enable-clocale=gnu --enable-languages=c,c++ --enable-multilib --disable-bootstrap --with-system-zlib Thread model: posix Supported LTO compression algorithms: zlib gcc version 13.2.0 (GCC)
Created attachment 57492 [details] Preprocessed output (gzipped to fit)
This is the expected behavior. Due to excessive precision for x87.
See PR 323 and other related bug reports.
(and -mfpmath=sse works.)
`0.0003 - 0.0001*3.0` with -std=c++23 is done all in long double and then casted to double. Which is why b is 0 there.
See explicitly pr 93112
And the first item at https://gcc.gnu.org/bugs/#nonbugs
I get all this, and thanks for quick processing. Still I think it's a bit odd that -std=c++* and -std?=gnu++* gives different results, but I assume there's a good reason for that. We'll be using -std=gnu++23 for now and move to 64 bit later as a solution for us.
See the first item at https://gcc.gnu.org/gcc-13/changes.html#cxx
-fexcess-precision=fast it is for now then, thanks again for fast feedback.
. *** This bug has been marked as a duplicate of bug 92875 ***
(In reply to Søren Jæger Hansen from comment #10) > -fexcess-precision=fast it is for now then, thanks again for fast feedback. -fexcess-precision is unrelated. Its goal is to choose whether GCC conforms to the standard, i.e. reduces the precision for assignments and casts (*only* in these cases, thus constants are not concerned), or generates faster but non-conforming code.
-fexcess-precision does affect constants. With -fexcess-precision=standard, assignments and casts discard excess precision which may otherwise be present in arithmetic expressions and constants. With -fexcess-precision=fast the excess precision might be retained even after casts and assignments, or it might be discarded at other points. But in both cases, a floating constant might have excess precision. Whether that excess precision is discarded, and when it's discarded, is affected by -fexcess-precision.
This bug is about "double/float constant evaluation" (and it has been marked as a duplicate of a bug precisely on this subject), not about the rules that are applied *after* this evaluation.
There is no bug, the compiler implements what the standard says for the FLT_EVAL_METHOD == 2 case. If you want in that mode a constant guaranteed to be in double precision, you need to explicitly cast the constant to double, otherwise it will have long double precision with type of double and that extra precision is only rounded to double precision on casts and assignments.
(In reply to Jakub Jelinek from comment #15) > There is no bug, the compiler implements what the standard says for the > FLT_EVAL_METHOD == 2 case. I agree. I meant this *invalid* bug.
(In reply to Jonathan Wakely from comment #13) > -fexcess-precision does affect constants. Indeed, and this is a bug, as -fexcess-precision=fast was not meant to make general programs less accurate (but to possibly keep more precision internally, avoiding costly conversions, even in cases where this is forbidden). See bug 114746.
(In reply to Vincent Lefèvre from comment #17) > (In reply to Jonathan Wakely from comment #13) > > -fexcess-precision does affect constants. > > Indeed, and this is a bug, as -fexcess-precision=fast was not meant to make > general programs less accurate (but to possibly keep more precision > internally, avoiding costly conversions, even in cases where this is > forbidden). See bug 114746. No that is NOT true.