Re: Strange behavior of -Wfloat-equal on clang (Xcode 5)
Re: Strange behavior of -Wfloat-equal on clang (Xcode 5)
- Subject: Re: Strange behavior of -Wfloat-equal on clang (Xcode 5)
- From: Fritz Anderson <email@hidden>
- Date: Fri, 03 Jan 2014 14:50:59 -0600
On 3 Jan 2014, at 12:28 PM, Asiga Nael <email@hidden> wrote:
> First of all, I don't understand why a==2.1 triggers the warning and a==2.0 doesn't. Why is 2.0 safer than 2.1? If 2.0 is a safe comparison, then 2.1 would be too.
## Summary
We're talking at cross-purposes.
You start with the sound and well-known principle that discrete numeric calculations are liable (and in real life probable) to accumulate rounding errors. As Kernighan and Plauger (The Elements of Programming Style, 1974) said, 10.0 times 0.1 is almost never 1.0. You can reframe the problem by replacing fixed floating-point increments with integer counters; you can mitigate it by thoughtful choice of numeric methods; you can defend against it by bracketing one of the operands with an epsilon interval. But a flat == against a float constant smells.
My point is that clang doesn't know about your numerical methods, or even whether the variable operand was derived by numerical methods; still less can it know whether what you are doing is wise. All it knows is that (a == 2.0) will behave reproducibly on all architectures (as a bonus, it is always correct); and (a == 2.1) will not. If not, it can report the portability issue. If we insisted on its having an opinion on the constant operand, it would probably be that round numbers may be flag values and not numeric results.
It's been the same with every C compiler since the '70s: You are assumed to know what you are doing, you are expected to know your problem domain, and the consequences are your responsibility.
> First of all, I don't understand why a==2.1 triggers the warning and a==2.0 doesn't. Why is 2.0 safer than 2.1? If 2.0 is a safe comparison, then 2.1 would be too.
2.1 has no exact representation in binary. Comparison to 2.0 may be a bad idea (as you ably discuss), but it can always be reduced to a consistent binary that does what the programmer _says_ he meant, with mathematical exactitude. Not the case with 2.1.
> I thought the reason for -Wfloat-equal is that comparing two floats for equality is always unsafe, no matter if such floats can have an exact integral representation or not.
As a practical matter, that isn't true. Anything with a mantissa that can be scaled to a binary integer (I haven't checked, but 1000.25 should work) has a binary representation that is equal to it in the rigorous, mathematical sense. Any other number that has that representation is equal to the first in the rigorous, mathematical sense. The == operator has no chance of error.
Again, it's _often_ "unsafe" as a practical matter of computing the variable operand. It depends on your intentions. clang can't know what your intentions are.
> Consider this example: Let's imagine a math application allows you to do some computations on unit vectors, which aren't available when the vector length isn't the unit. The application needs to check the vector length against 1.0. Doing it using the == operator is unsafe (a vector resulting from a lot of math won't exactly equal 1.0 even if it can be legitimately called a unit vector).
Again, that's a limitation of whether your numerical methods accumulate rounding errors — a limitation that, in this case, any competent programmer would understand. Not knowing the origin or domain constraints of the computed length, clang can't match your knowledge of whether testing for equality is wise. All it knows is that consistent, correct code for what you told it to do is possible.
> Another example: a decremental loop with a floating point counter, with the end condition set to equal 0.0 (the loop would be unsafe, as it could get out of bounds depending on the implementation).
Again, a matter of numerics. And the process in your example isn't merely "not competent," it's brain-dead. And the comparison to 0.0 is, as a matter of code generation (which is all that clang knows), reproducible and exact.
> I cannot think of any safe examples when comparing floats to exact constants.
And then you come up with an example that you say you use all the time:
if (valueOrZero == 0.0) ratio = fNumerator / valueOrZero;
So you do it, too. We're just haggling over price.
> (and, btw, maybe they aren't false positives, because I'm not sure if a float which isn't exactly equal to 0.0 can be used as denominator with a certain guarantee that it doesn't generate infinity: maybe a very close to zero value can become infinity when used as denominator... I'm not sure about this).
Discrete arithmetic. It's possible to overflow the representation, as by (sufficientlyHuge / sufficientlyTiny). Different architectures, and different exception flags within an architecture, do different things, like raising a signal; returning a NaN (maybe decorated with a positive-overflow flag); returning an infinity of a sign that might be guessed from the numerator (a bad idea); or returning HUGE_VAL (an appalling idea, but I'm sure someone has tried it).
— F
_______________________________________________
Do not post admin requests to the list. They will be ignored.
Xcode-users mailing list (email@hidden)
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden