Zero floating point in C implementations (IEEE 754 invariants?)

I have the following C expression (variables are 32 bit floats)

float result = (x1 - x0) * (y2 - y0) - (x2 - x0) * (y1 - y0) 

Assuming that x0==x1 and y0==y1 , (and with == I mean the binary representation identifier), can I rely on the fact that the expression is necessarily evaluated to zero (as in all bits, the float is set to 0 )? In other words, can I assume that invariants always remain?

 memcmp(&a, &b, sizeof(float) == 0 => memcmp(ab, (uint32_t)0, sizeof(float)) == 0 0*a == 0.0 

It is safe to assume that all values ​​are finite numbers (without INFINITY or NaN).

Edit: As indicated in the answers, multiplications from 0 can cause signed zeros. Can I still rely on the result of the expression to be 0.0 using the FP comparison rules, i.e.:

 (result == 0.0) 

Edit 1: Replace types with an application using memcmp calls to better illustrate the issue.

PS I limit my code only to compatible C11 compilers, if that matters. I am also willing to rely on STDC_IEC_559 support if this helps my case.

+5
source share
1 answer

Mentioning C11 just confuses your question because IEEE 754 is not required by any C standard.

However, assuming only 32-bit floating point numbers of IEEE 754 and not making assumptions on x2 and y2 (except for those that are not infinite or NaN), you cannot assume that all bits of the result will be 0. The number of IEEE 754 has two zeros, one negative and one positive, and if the expression (y2 - y0) - (x2 - x0) negative, the result of multiplying it by zero will be a negative zero.

We can verify this with this short example:

 #include <stdio.h> #include <stdint.h> int main(int argc, char **argv) { union { float f; uint32_t i; } foo; float a = 0; float b = -1; foo.f = a * b; printf("0x%x\n", foo.i); return 0; } 

Result (don't notice the optimization, since I don't want the compiler to be smart):

 $ cc -o foo foo.c && ./foo 0x80000000 

Oh, I just noticed that the second part of your question, which you called "in other words", is not really other words, because it is a different question.

To start:

 (*(uint32_t*)(&a) == *(uint32_t*)(&b)) 

not equivalent a == b for floating point, because -0 == 0 . And in doing so, the other part of the assumption breaks up because -0 - 0 gives you -0 . I can not do another subtraction of equal numbers, generating a negative zero, but this does not mean that it is impossible, I am sure that the standards do not use the same algorithm for subtraction in all implementations, so the sign bit could sneak there somehow.

+4
source

All Articles