Live data from Hacker News

GNU GCC does not round floating-point divisions to the nearest value

lemire.me

21–30 of 87 posts

Re: GNU GCC does not round floating-point divisions to the nearest value

#22
post #18
post #13

Perhaps the title should mention that this is 32-bit x86, which is rather obsolete. This should work okay on x86_64.

Are you sure? The FPU instruction set is the same.

I just checked on the linked Compiler Explorer session [0], and if you take out the -m32 then GCC does indeed use divsd instead of fdiv.

[0] https://godbolt.org/z/py3Dw0

Re: GNU GCC does not round floating-point divisions to the nearest value

#23

If you add '-ffast-math' to the compiler parameters in his godbolt link you get the 'right' answer. Doing that means the division is done with the 'divsd' instruction, which clang uses even without the 'fast-math' flag. That doesn't mean it's necessarily the right thing to do though. Clang can be made generate the same code as the 'broken' gcc output by declaring the variables as 'long double' instead of 'double'. So…

-ffast-math should rebrand itself to -ffast-and-more-correct-math ;)

It’s normally not more correct.

Re: GNU GCC does not round floating-point divisions to the nearest value

#24

I believe the issue is that some of this ends up evaluated at compile-time, and the compiler really has no idea how to do rounding correctly at that point. When implementing floating point tests for an x86 emulator, we had to create a macro that would ensure that the calculation was done at runtime rather than at compile time for this exact reason: https://github.com/ish-app/ish/blob/18176b6931d69bdabe48f137... . If…

[deleted]

Re: GNU GCC does not round floating-point divisions to the nearest value

#25
post #18
post #13

Perhaps the title should mention that this is 32-bit x86, which is rather obsolete. This should work okay on x86_64.

Are you sure? The FPU instruction set is the same.

Yes. Toggle -m32 (compiles to 32 bit) or deleting it. (defaults to 64 bit, because it's not 2005 anymore) It also works with -m32 -mfpmath=sse, even though the author of the article incorrectly states otherwise.

https://godbolt.org/z/py3Dw0

Re: GNU GCC does not round floating-point divisions to the nearest value

#27
If you're interested in the accuracy of floating point operations, I recommend taking a look at the khronos openCL[1], it's not as clear cut as you would think. I think there are good reasons not to expect floating point ot be bit accurate.

[1]:https://www.khronos.org/registry/OpenCL/specs/2.2/html/OpenC...

Re: GNU GCC does not round floating-point divisions to the nearest value

#28
post #18
post #13

Perhaps the title should mention that this is 32-bit x86, which is rather obsolete. This should work okay on x86_64.

Are you sure? The FPU instruction set is the same.

The platform ABI can differ on the same cpu.

I originally had the wrong answer here, but I'm including below for historical purposes and embarrassment. Re-reading on my laptop meant I didn't misread/read-the-expected?

Basically by default when compiling for IA32 gcc assumes that there is no SSE unit, and so must use the x87 fpu.

Alas the x87 unit doesn't have either 32 or 64 bit ieee floating point types, so the calculation at runtime must be rounded to float/double at the end of the computation. That results in a double round that is incorrect.

Minor additional comment - x87's reduced precision modes (that reduce mantissa precision to ieee754-32/64) don't reduce the exponent size so it's conceivable you could get multiple-rounding derived errors even then. But no one would be toggling x87 state like that anyway, so theoretically not something that would matter in most cases.

Old incorrect answer:

On ia32 long double is the x87 80bit ieee754 numeric type.

On x86_64 on windows, and maybe Linux, long double is just a 64bit ieee float.

So my guess is that GCC computes constant evaluation of floating point expressions in “long double” for maximum precision, and then rounds to the required precision at the end. This is not valid going from 64->32 bit floats and you could probably induce this bug if you tried hard enough.

Anyway it is not sound to round twice in any numeric operation, and by doing the calculation at one precision and then rounding that to the required precision that is what gcc is doing.

This is a bug in GCC, floating point is well defined, there isn’t randomness to it, and they’ve introduced additional rounding that is not valid.

Re: GNU GCC does not round floating-point divisions to the nearest value

#29
x87 is crazy. Especially since you can’t easily know when something is truncated from 80 bits to 64. Add a parameter to a function and an unrelated calculation behaves differently because it now ran out of 80bit registers. Congratulations, you now have a spurious test failure you will spend weeks trying to find.

The only way of doing FP on x86 and keeping your sanity is by making sure you use 32/64 bit floats 100% of the time. That is: use SSE registers and never the 80-bit x87 arithmetic.

I thought compilers for 64 bit programs these days did exactly this. I know the .NET Jit does for example.

Re: GNU GCC does not round floating-point divisions to the nearest value

#30
As I understand it, the IEEE floating point standards do not require exact rounding for binary to decimal conversions. See What Every Computer Scientist Should Know About Floating-Point Arithmetic https://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.h...

The behavior appears to be consistent with the standard. Keep in mind that GCC needs to provide the same result irrespective of the architecture it runs on and one reason to use GCC for floating point is to take advantage of dedicated hardware. And the reason to use floating point is speed not precision (at least when using decimal floating point). If precision is critical then arbitrary precision or fixed point is the way to go. Normally it isn’t that critical.

Post reply on HN