C ++ additive identity unsafe example (a + 0.0! = A)

The MSDN article mentions when fp: fast mode is enabled, operations such as incremental identifier ( aΒ±0.0 = a , 0.0-a = -a ) are not safe. Is there any example that a+0 != a in this mode?

EDIT: As mentioned below, such a problem usually occurs when comparing. My problem is in comparison, psedocode is as follows:

 for(i=0;i<v.len;i++) { sum+=v[i]; if( sum >= threshold) break; } 

It breaks after adding the value 0 ( v[i] ). v[i] not calculated, he is appointed. I understand that if my v[i] is the result of the calculation, rounding can come into play, but why, although I give v[i] null value, I still have sum < threshold , but sum + v[i] >= threshold ?

+7
c ++ floating-point unsafe
source share
4 answers

he mentions when fp: fast mode is enabled, operations such as additive identity (a Β± 0.0 = a, 0.0-a = -a) are not safe.

This article says:

The optimizer can use any of the following (unsafe) algebraic rules if fp: fast mode is enabled:

And then it lists Β± 0.0 = a and 0.0-a = -a

This is not to say that these identifiers are unsafe when the fp: fast function is enabled. These identities are said to be incorrect for IEEE 754 floating point arithmetic, but this / fp: fast will be optimized as if they were true.

I'm not sure about an example that shows that a + 0.0 == a is false (except for NaN, obviously), but IEEE 754 has many subtleties, for example, when intermediate values ​​need to be truncated. One possibility is that if you have some kind of expression that includes + 0.0 , this may lead to the requirement in IEEE 754 to truncate an intermediate value, but that / fp: fast will generate code that does not truncate. and therefore, later results may differ from what is strictly required by IEEE 754.


Using Pascal Cuoq info here is a program that produces different output based on / fp: fast

 #include <cmath> #include <iostream> int main() { volatile double a = -0.0; if (_copysign(1.0, a + 0.0) == _copysign(1.0, 0.0)) { std::cout << "correct IEEE 754 results\n"; } else { std::cout << "result not IEEE 754 conformant\n"; } } 

When building with / fp: quickly, the outputs of the program "do not match IEEE 754" when building with / fp: strict cause the program to output "the correct IEEE 754 results."

+1
source share

The reason it is "unsafe" is because the compiler assumes that it is zero, it may not be zero due to rounding errors.

Take this example, which adds two floats at the precision border that 32 bits allow:

  float a = 33554430, b = 16777215; float x = a + b; float y = x - a - b; float z = 1; z = z + y; 

Using fp: fast, the compiler says "since x = a + b, y = x - a - b = 0, so" z + y "is just z". However, due to rounding errors, y actually ends with -1, not 0. Thus, you get a different result without fp: fast.

+3
source share

This does not say something "fixed" as "if you set / fp: fast and the variable a is 3.12345, then a + 0 may not be." This suggests that when you install / fp: fast, the compiler will use shortcuts, which means that if you calculate a + 0 and then compare it with what you saved for a, there is no guarantee that they will be the same .

In this class of problems (which are endemic to floating point computing on computers) there is a large entry: http://www.parashift.com/c++-faq-lite/floating-point-arith2.html

+2
source share

If a is 0.0 , then a + 0.0 is +0.0.

+2
source share

All Articles