Search code examples
c++optimizationfloating-pointieee-754double-double-arithmetic

Can I guarantee the C++ compiler will not reorder my calculations?


I'm currently reading through the excellent Library for Double-Double and Quad-Double Arithmetic paper, and in the first few lines I notice they perform a sum in the following way:

std::pair<double, double> TwoSum(double a, double b)
{
    double s = a + b;
    double v = s - a;
    double e = (a - (s - v)) + (b - v);
    return std::make_pair(s, e);
}

The calculation of the error, e, relies on the fact that the calculation follows that order of operations exactly because of the non-associative properties of IEEE-754 floating point math.

If I compile this within a modern optimizing C++ compiler (e.g. MSVC or gcc), can I be ensured that the compiler won't optimize out the way this calculation is done?

Secondly, is this guaranteed anywhere within the C++ standard?


Solution

  • Yes, that is safe (at least in this case). You only use two "operators" there, the primary expression (something) and the binary something +/- something (additive).

    Section 1.9 Program execution (of C++0x N3092) states:

    Operators can be regrouped according to the usual mathematical rules only where the operators really are associative or commutative.

    In terms of the grouping, 5.1 Primary expressions states:

    A parenthesized expression is a primary expression whose type and value are identical to those of the enclosed expression. ... The parenthesized expression can be used in exactly the same contexts as those where the enclosed expression can be used, and with the same meaning, except as otherwise indicated.

    I believe the use of the word "identical" in that quote requires a conforming implementation to guarantee that it will be executed in the specified order unless another order can give the exact same results.

    And for adding and subtracting, section 5.7 Additive operators has:

    The additive operators + and - group left-to-right.

    So the standard dictates the results. If the compiler can ascertain that the same results can be obtained with different ordering of the operations then it may re-arrange them. But whether this happens or not, you will not be able to discern a difference.