Live data from Hacker News

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

lemire.me

81–87 of 87 posts

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

#82
post #19
post #4

Earlier quoted context omitted.

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 enviro…

There is a lot of Python out there running in embedded environments, some quite old. Python is 30 years old after all.

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

#83
post #51

Earlier quoted context omitted.

Why would there be any difference?

Because every x86_64 CPU supports SSE2, so compilers can assume it exists and the ABI passes floating point arguments in SSE2’s FP registers. This means that every sane compiler for x86_64 will use SSE2 and won’t use x87, and the problem won’t occur. In contrast, the 32-bit C ABI passes floating point args in x87 registers, and there are 32-bit CPUs without SSE2, so x87 is used by default. x87 is, in quite a few resp…

[deleted]

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

#84

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…

Look for the heading, “The IEEE Standard” in “What Every Computer Scientist Should Know About Floating-Point Arithmetic,” then scroll down to the subheading “Operations.” That section begins, “The IEEE standard requires that the result of addition, subtraction, multiplication and division be exactly rounded. That is, the result must be computed exactly and then rounded to the nearest floating-point number (using roun…

Yes, you are correct. Thanks. This stuff is hard for me.

Reading down thread, I see that the behavior might be related to x87 since the build script references i386...which makes IEEE 754 conformance moot. The methods of achieving conformance when targeting i386 are described in the GCC documentation.

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

#85

Earlier quoted context omitted.

It’s normally not more correct.

I thought fast-math meant (among other things) that the compiler could algebraically simplify things using some rules for real numbers that don't apply to 32-/64-bit floating point numbers. I'd expect that reducing the number of operations would more often than not reduce the error due to rounding, which is what most people would want when they talk about "correctness". Which step in this (very naive) argument is wro…

One very language-lawyer way to look at it is that, even if the answer it gives is more mathematically accurate, it's still less correct in that it's not the value you literally asked for.

Imagine the analogue for integers. You might use code like this to round down to a multiple of 2:

    int i = 7;
    int j = (i / 2) * 2;
If a compiler optimized that to j = i then that's more mathematically accurate but less correct.

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

#86
post #51

Earlier quoted context omitted.

Because every x86_64 CPU supports SSE2, so compilers can assume it exists and the ABI passes floating point arguments in SSE2’s FP registers. This means that every sane compiler for x86_64 will use SSE2 and won’t use x87, and the problem won’t occur. In contrast, the 32-bit C ABI passes floating point args in x87 registers, and there are 32-bit CPUs without SSE2, so x87 is used by default. x87 is, in quite a few resp…

For the Linux kernel, things get slightly more complicated with -mgeneral-regs-only. ( https://bugs.llvm.org/show_bug.cgi?id=30792 / https://reviews.llvm.org/D38479 ). A few drivers use floating point values/calculations. Which way are they rounded when expressions are folded at compile time? Does that match what would happen at runtime? The x86 kernel also disables SSE generally (kernel_fpu_{begin|end} via -mno-{x87…

> For the Linux kernel, things get slightly more complicated with -mgeneral-regs-only. (https://bugs.llvm.org/show_bug.cgi?id=30792 / https://reviews.llvm.org/D38479).

That looks like an ARM issue.

> Further, it uses an 8B stack alignment, which makes it so that when FP is used, the compiler cannot select instructions that require 16B aligned operands to be loaded/stored from/to the stack.

On x86_64, on a recent GCC, this all works correctly. If you end up with a 16-byte-aligned variable (like an SSE vector) on the stack, GCC will correctly align the stack in the prologue. On older GCCs, there were a serious of obnoxious I-know-better-than-you-isms in the command line option handling that made this all malfunction.

I seem to be missing the Share button on godbolt.org, so no link. But you can test with:

    typedef int v4si __attribute__ ((vector_size (16)));
    v4si *v;
    
    int func(void)
    {
        v4si z;
        v = &z;
    
        return 0;
    }
Add -mpreferred-stack-boundary=3 to the options.

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

#87
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?

Python IIRC stores intermediate results in memory, it doesn't perform long chains of calculations entirely in FPU registers. This ensures the intermediate results are predictably rounded.

JavaScript JITs blindly use SSE without checking if it is available. Bytecode interpreters behave the same as above.

Post reply on HN