문제

In MSDN article, it mentions when fp:fast mode is enabled, operations like additive identity (a±0.0 = a, 0.0-a = -a) are unsafe. Is there any example that a+0 != a under such mode?

EDIT: As someone mentioned below, this sort of issue normally comes up when doing comparison. My issue is from comparison, the psedocode looks like below:

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

It breaks after adding a value of 0 (v[i]). The v[i] is not from calculation, it is assigned. I understand if my v[i] is from calculation then rounding might come into play, but why even though I give v[i] a zero value, I still have this sum < threshold but sum + v[i] >= threshold?

도움이 되었습니까?

해결책 4

it mentions when fp:fast mode is enabled, operations like additive identity (a±0.0 = a, 0.0-a = -a) is unsafe.

What that article says is

Any of the following (unsafe) algebraic rules may be employed by the optimizer when the fp:fast mode is enabled:

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

It is not saying that these identities are unsafe when fp:fast is enabled. It is saying that these identities are not true for IEEE 754 floating point arithmetic but that /fp:fast will optimize as though they are true.

I'm not certain of an example that shows that a + 0.0 == a to be false (except for NaN, obviously), but IEEE 754 has a lot of subtleties, such as when intermediate values should be truncated. One possibility is that if you have some expression that includes + 0.0, that might result in a requirement under IEEE 754 to do truncation on an intermediate value, but that /fp:fast will generate code that doesn't do the truncation, and consequently later results may differ from what is strictly required by IEEE 754.


Using Pascal Cuoq's info here's 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 built with /fp:fast the program outputs "result not IEEE 754 conformant" while building with /fp:strict cause the program to output "correct IEEE 754 results".

다른 팁

The reason that it's "unsafe" is that what the compiler assumes to be zero may not really end up being zero, due to rounding errors.

Take this example which adds two floats on the edge of the precision which 32 bit floats allows:

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

With 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 up being -1, not 0. So you would get a different result without fp:fast.

It's not saying something 'fixed' like, "if you set /fp:fast, and variable a happens to be 3.12345, then a+0 might not be a". It's saying that when you set /fp:fast, the compiler will take shortcuts that mean that if you compute a+0, and then compare that to what you stored for a, there is no guarantee that they'll be the same.

There is a great write up on this class of problems (which are endemic to floating point calculations on computers) here: http://www.parashift.com/c++-faq-lite/floating-point-arith2.html

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

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top