Live data from Hacker News

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

lemire.me

11–20 of 87 posts

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

#12
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 anyone knows how to control floating point rounding in C reliably, I'd be interesting in hearing it :)

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

#14
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 I think this is where the issue lies?

Edit: godbolt link requiring large monitor: https://godbolt.org/z/tFiZwW

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

#15
An example where this matters -- a new Mario 64 trick on the Virtual Console version because summing round-towards-zero numbers over a sine wave cycle produces a small delta which builds up over a couple of days to make a jump possible

https://www.kotaku.com.au/2018/06/the-mario-64-trick-that-ta...

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

#16
post #5
post #2

This seems like a property of the Intel 8087 math coprocessor and its distant descendants found in x86 chips, not anything to do with gcc?

My understanding is that in this case it's GCC's optimizer evaluating the expression at compile time in a way that gives a different result to if it's done at runtime. EDIT: GCC gets it wrong with -O0 (when it's evaluated at runtime) and right with -O2 (when it evaluates it at compile time) Clang appears to get it right when evaluated at compile time or runtime. Clang uses the divsd instruction; GCC uses the fdiv ins…

clang gets it "right" because it uses the sse divsd instruction to perform the division, gcc gets it "wrong" because it uses the x87 fdiv instruction.

You can configure gcc to use sse math with the -mfpmath=sse instruction. The author states that gcc still gets it "wrong" but he simply is not correct. gcc will use divsd and gets 0.501782303180000055.

gcc defaults to use the x87 fpu instead of sse because not all 32 bit x86 cpus have SSE instructions. It's a safer default. When compiled in 64 bit mode, it uses up to SSE2 instructions, because all x86_64 CPUs have SSE2.

https://godbolt.org/z/3PfKQU

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

#17

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 ;)

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

#19
post #4
post #2

This seems like a property of the Intel 8087 math coprocessor and its distant descendants found in x86 chips, not anything to do with gcc?

But then why does python and JavaScript on the same machines get it right?

Because they're compiled to use SSE instructions instead of x87 FPU instructions.

If you are still writing 32 bit x86 C code, it's probably some embedded or legacy CPU, and it's wrong to assume SSE instructions are available. So GCC correctly defaults to using FPU instructions instead of SSE instructions on 32 bit x86.

Javascript and python will basically never be run in embedded environments, and their legacy environments probably aren't that legacy that SSE instructions aren't available. So it's reasonable to default to SSE.

Post reply on HN