Compiler Warnings
fastcompression.blogspot.com
fastcompression.blogspot.com
I like to use diagnostic pragmas (https://gcc.gnu.org/onlinedocs/gcc/Diagnostic-Pragmas.html) in the vanishingly rare cases where I can't fix the cause of a warning.
Don't know what the situation is on MS's and Intel's compilers.
There are still edge cases where you can't sanely scope them relating to when templates are evaluated, being unable to use the pragmas at arbitrary points of an expression, warnings that don't respect the warning flags properly, etc. - but it works most of the time.
That said, for warnings with high false positives and low value true positives, I'll just globally suppress the warning.
This option is rather for developers who want to avoid declarations after statements in C dialects that support them.
If you want to enforce actual C90 compatibility use -ansi or -std=c90. Otherwise you just have partial compatibility which is actually incompatibility.
Floating point is completely deterministic, and has a very clearly defined set of behaviours.
Sure, if the same system runs the same operation twice, the two values will be equal. But what if you're comparing to a stored value generated on a different system?
The problems stem from running under different rounding modes on different systems, I believe at this point literally all platforms default to RTE, and if you’re working with a different rounding mode your errors are going to be much more significant than “compare to epsilon”.
The historic problems people have had with C compilers and floating point is that compiler vendors seem hell bent on “improving” performance by effectively changing clearly intended semantics (eg the compiler is an adversary). These include performing calculations at an incorrect precision (eg host precision, “convenient” precision) rather than the specified precision, or bizarrely treating floating point arithmetic as commutative and associative. That bit of behavior isn’t specific to floating point - c compilers routinely optimize out security checks because they taken “undefined” to mean “free to change clear intent”.
x86 is extremely popular and 80 bit long doubles using the old FPU model can introduce weirdness on that platform. And yes, reducing the 80 bit long doubles to 64 bits after every operation significantly impacts performance. Or used to.
But my point was that saying floating point was somehow a magical non-deterministic beast is incorrect, and saying == shouldn't be allowed because of that is incorrect. Pretty much the same arguments can be made for integer arithmetic (after all x/y is undefined behavior if it overflows or y is zero even for integers, and just as with floating point you need to understand the behavior of arithmetic)
In contrast, the result of basic floating point operations is not. You may live in a world were you use a single cpu type, and a single OS, and a single compiler, in which case, it might appear to you as defined. But anyone involved in some portability across multiple systems know how improbable it is to rely on floating point for anything exact. Actually, don't. ever.
For anything which requires exact results, use integer instead.
Things that differ: bit wise representation for non-ieee formats. Things that don’t differ: numeric result.
Basically for any arithmetic operation, with a given significand and exponent size in some rounding mode, there is a single correct result. Different implementations do not produce different results.
Additionally, many usages of == assume basic algebraic properties of numbers to hold.
It is possible to use equality with floats, but require far more care than is typically worth it.
As an aside, if your concern is that the standards impose too much restrictions, another popular option is the ffast-math option.
We see this come up with strings fairly often in higher level languages where, sometimes, logical equal strings will happen to be equal because the runtime's interning system made them point to the same location, but there is no guarantee this would happen and the implementation is free to change it at any point. I believe I have also seen this behaviour come up with interning on some Integer wrapper types.
The C abstract machine defines the behavior, and optimization passes aren't allowed to change the behavior.
-ffast-math is the option that allows incorrect semantics (e.g commutative floating point addition), but compilers have a desire to do incorrect things for "performance".
I would hope it is obvious that changing behavior for performance isn't ok, but lets say it was. A compiler could change
y=1.0/fsqrt(x)
from (v. approximate, untested, and written in a text box :D)
movsd xmm0, $(wherever x is) sqrtsd xmm0 movsd xmm1, $(location of 1.0 constant) divsd xmm1, xmm0 movsd $(addr of y), xmm1
to something like
movsd xmm0, $(wherever x is) rsqrtsd xmm0 movsd $(addr of y), xmm0
This would be much much faster, and vastly incorrect (IIRC rsqrt is only 12bits of precision)
Or even more dumb, remove calls to printf, because printf is slow.
A compiler does not have absolute leeway in all things, it is still restricted to ensuring that observable results of the C abstract machine are correct.
Python, for example:
>>> 8 is 8
True
>>> 8**1000 is 8**1000
False >>> [] == False
False
>>> object() == False
False
>>> "" == False
False
>>> {} == False
False
They're just different.You are of course right :)