简体   繁体   中英

Can we assume any pair of following floating point arithmetic statements always produce identical result?

Given following floating points variables with arbitrary value, in c/c++.

float a, b, c, d;

In following statements, can we assume any pair of them would always generate identical result?

float result_1 = a + b + c + d - c;
float result_2= a + b + c + (d - c);
float result_3 = a + b + d;

Also, is there any guarantee on following predicate:

a + b - b == a

No, you can not assume this. I broke all three of your examples: (Live)

#include <iostream>

int main()
{
   double a = 1, b = 1e100, c= 1e100, d= 1, c2 = .1, d2 = -.1, b2 = 1;

   std::cout << ( a + b2 + c2 + d2 - c2 == a + b2 + c2 + (d2 - c2)) << "\n"
    << ( a + b2 + c + d - c == a + b2 + d) << "\n"
    << ( a == a + b -b);
}

Output:

0 0 0

== and != are always unsafe on floating point types because the have rounding errors.

First, we make state the standard caveats about float point numbers on computers. They are inherently imprecise. There's just no way to accurately say ".1" in binary. So, any of those may give you a "wrong" answer. But, in general, they should give you the same wrong answer.

In general, you'll have more variation with multiplication and division than with addition and substraction. And, you'll ofton run into trouble dealing with very large numbers and very small numbers in the same calculation.

[update] This next sentence is wrong. Ignore it:
However, as far as I can see, in this limit context, it seems everything balances out correctly, so while I can't say it categorically, I think you're safe here.

If I run the following code:

#include <stdio.h>

int main(int argc, char* argv[])
{
    float a = 0.1;
    float b = 0.2;
    float c = 0.3;
    float d = 0.4;

    float result1 = a + b + c + d - c;
    float result2 = a + b + c + (d - c);
    float result3 = a + b + d;

    printf("result1 == result2: %s\n", result1 == result2 ? "Yes" : "No");
    printf("result2 == result3: %s\n", result2 == result3 ? "Yes" : "No");
    printf("result1 == result3: %s\n\n", result1 == result3 ? "Yes" : "No");

    printf("result1: %30.20f\n", result1);
    printf("result2: %30.20f\n", result2);
    printf("result3: %30.20f\n\n", result3);

    printf("a + b:               %30.20f\n", a + b);
    printf("a + b + c:           %30.20f\n", a + b + c);
    printf("a + b + c + d:       %30.20f\n", a + b + c + d);
    printf("d - c:               %30.20f\n", d - c);
    printf("a + b + c + d - c:   %30.20f\n", a + b + c + d - c);
    printf("a + b + c + (d - c): %30.20f\n", a + b + c + (d - c));
    printf("a + b + d:           %30.20f\n", a + b + d);

    return 0;
}

I get the following output, showing that the answer to your main question is NO :

result1 == result2: No
result2 == result3: Yes
result1 == result3: No

result1:         0.69999998807907104492
result2:         0.70000004768371582031
result3:         0.70000004768371582031

a + b:                       0.30000001192092895508
a + b + c:                   0.60000002384185791016
a + b + c + d:               1.00000000000000000000
d - c:                       0.09999999403953552246
a + b + c + d - c:           0.69999998807907104492
a + b + c + (d - c):         0.70000004768371582031
a + b + d:                   0.70000004768371582031

Compiler: Apple LLVM 5.1 (clang).

I get the same results with one, but not with another compiler I tried with. The last one uses the x86 FPU in 32 bit code. The other two run in 64 bit mode and use SSE2, AFAIK.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM