0

I have two vectors of double. The value of the double is between -1000 and 1000.

Both vectors contain the same numbers, but the order is different.

For example

Vector1 = {0.1, 0.2, 0.3, 0.4};
Vector2 = {0.4, 0.2, 0.1, 0.3};

Is there a guarantee that the sum of Vector1 will be exactly equal to the sum of Vector2, assuming the sum is done via:

double Sum = 0;
for (double Val : Vector) Sum += Val;

I am worried about double imprecisions.

RainingChain
  • 7,397
  • 10
  • 36
  • 68
  • 3
    Is there a guarantee? No, probably not. If you want exact arithmetic, don't use floating point. – Paul Sanders Feb 01 '22 at 23:05
  • NO! Read https://stackoverflow.com/questions/588004/is-floating-point-math-broken – Marek R Feb 01 '22 at 23:08
  • 1
    The guarantee is **not possible** for fixed-precision floating-point numbers, in any language, period. Look for a paper titled "what every computer scientist should know about floating-point arithmetic". – Kaz Feb 01 '22 at 23:09
  • Well, the guarantee is possible in silly ways. For instance, wherever three or more floating-point numbers are being added, the compiler could emit code to put them into an array, then **sort** them in some way and then add them from left to right. Everyone would hate that because it would be slow, and yield unpredictable results due to the order being different whenever the code is called with different values. – Kaz Feb 01 '22 at 23:13
  • 1
    duplicates: [Floating-point arithmetic: why would order of addition matter?](https://stackoverflow.com/q/48957828/995714), [Why does changing the sum order returns a different result?](https://stackoverflow.com/q/19820297/995714), [Why does the order affect the rounding when adding multiple doubles](https://stackoverflow.com/q/696769/995714), [Different results when adding same doubles in different order](https://stackoverflow.com/q/21373865/995714) – phuclv Feb 01 '22 at 23:33
  • If you sort the numbers first and then add from smallest to largest you get the most accurate result and that should be consistent from run to run. But optimizations can even affect the results as registers may store more significant values than memory locations. – Martin York Feb 01 '22 at 23:45
  • @MartinYork smallest to largest in magnitude; not the signed value (in general case; not just considering the example numbers). But even then, that's just a decent heuristic and not optimally precise. You can often get better precision with multiple intermediate results. – eerorika Feb 01 '22 at 23:55
  • *I am worried about double imprecisions* -- Don't use `double`. If you are dealing with money or financial calculations where the arithmetic must be exact, then you can't and should not use floating point. – PaulMcKenzie Feb 02 '22 at 00:09
  • If you're worried about "double imprecisions" then don't use floating point. Imprecision of operations (and propagation of imprecision) is an intrinsic property of floating point types, which needs to be managed in algorithm design to control its effects. – Peter Feb 02 '22 at 00:19

3 Answers3

3

Is there a guarantee that the sum of Vector1 will be exactly equal to the sum of Vector2, assuming the sum is done via:

No, there is no such guarantee in the C++ language.

In fact, there is an indirect practical guarantee - assuming typical floating point implementation - that the results would be unequal. (But compilers have ways of disabling such guarantees, and of enabling unsafe floating point optimisations that may cause the sum to be equal).

The difference is likely to be very small with the given input, but it can be very large with other inputs.

eerorika
  • 232,697
  • 12
  • 197
  • 326
2

No, they are not guaranteed to be the same. Here's a simple concrete example:

#include <stdio.h>

int main(void) {
    double x =  504.4883585687764;
    double y = 29.585946026264367;
    double z =   2.91427392498775;

    double lhs = x + (y + z);
    double rhs = z + (y + x);

    printf("LHS  : %5.30g\n", lhs);
    printf("RHS  : %5.30g\n", rhs);
    printf("Equal: %s\n", lhs == rhs ? "yes" : "no");
    return 0;
};

When run, this produces:

LHS  : 536.988578520028568163979798555
RHS  : 536.988578520028454477142076939
Equal: no
alias
  • 28,120
  • 2
  • 23
  • 40
1

Read this and in general something about floating points.

Note that if you adding value of different magnitude they will be rounded in different way if order is changed giving a bit different result.

Marek R
  • 32,568
  • 6
  • 55
  • 140