Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 905
Mike Bailey Avatar asked Oct 05 '11 02:10

Mike Bailey


People also ask

Can compiler reorder function calls?

If you mean that the difference can not be observed, then yes, the compiler (and even the CPU itself) is free to reorder the operations.

Can GCC reorder function calls?

GCC can change the order of functions, because the C standard (e.g. n1570 or newer) allows to do that. In practice (with optimizations enabled: try compiling foo. c with gcc -Wall -fverbose-asm -O3 foo.

Does compiler optimize code?

Compilers are free to optimize code so long as they can guarantee the semantics of the code are not changed. I would suggestion starting at the Compiler optimization wikipedia page as there are many different kinds of optimization that are performed at many different stages.

Does GCC optimize code?

GCC has a range of optimization levels, plus individual options to enable or disable particular optimizations. The overall compiler optimization level is controlled by the command line option -On, where n is the required optimization level, as follows: -O0 . (default).


3 Answers

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.

like image 100
paxdiablo Avatar answered Oct 26 '22 12:10

paxdiablo


If you really need to, I think you can make a noinline function no_reorder(float x) { return x; }, and then use it instead of parenthesis. Obviously, it's not a particularly efficient solution though.

like image 43
Anton Knyazyev Avatar answered Oct 26 '22 11:10

Anton Knyazyev


I would be quite surprised if any compiler wrongly assumed associativity of arithmetic operators with default optimising options.

But be wary of extended precision of FP registers.

Consult compiler documentation on how to ensure that FP values do not have extended precision.

like image 30
curiousguy Avatar answered Oct 26 '22 12:10

curiousguy