Can I guarantee that the C ++ compiler does not change the order of my calculations?

I am currently reading the excellent Library for Double-Double and Quad-Double Arithmetic , and in the first few lines I notice they are performing the sum as follows:

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 based on the fact that the calculation follows the order of operations precisely because of the non-associative properties of IEEE-754 floating point mathematics.

If I compile it within the framework of the modern optimizing C ++ compiler (for example, MSVC or gcc), can I be sure that the compiler will not optimize the way this calculation is performed?

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

+6
source share
10 answers

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

Section 1.9 Program execution (from C ++ 0x N3092) reads:

Operators can be rearranged in accordance with normal mathematical rules only in cases where the operators are indeed associative or commutative.

In terms of grouping 5.1 Primary expressions indicates:

An expression in parentheses is the main expression, the type and value of which are identical to the type of the enclosed expression ... An expression enclosed in parentheses can be used in exactly the same contexts as those in which a closed expression can be used, and with the same value , unless otherwise specified.

I believe that the use of the word β€œidentical” in this citation requires a coordinated implementation to ensure that it is executed in the indicated order if a different order cannot give accurate results.

And for addition and subtraction, section 5.7 Additive operators has:

Additive operators + and - group from left to right.

Thus, the standard dictates the results. If the compiler can make sure that the same results can be obtained with different ordering of operations, then he can reorder them. But whether this happens or not, you cannot distinguish the difference.

+3
source

You might like the g ++ man page: http://gcc.gnu.org/onlinedocs/gcc-4.6.1/gcc/Optimize-Options.html#Optimize-Options

In particular, -based mathematics, -fast mathematics and -float-shop

According to the g ++ manual, it will not reorder your expression unless you specifically request it.

+6
source

This is a very topical issue, because the Intel C ++ compiler, which is very widely used, by default performs optimization, which can change the result.

See http://software.intel.com/sites/products/documentation/hpc/compilerpro/en-us/cpp/lin/compiler_c/copts/common_options/option_fp_model.htm#option_fp_model

+5
source

I would be very surprised if any compiler mistook the associativity of arithmetic operators with default optimization parameters.

But one should beware of the extended precision of FP registers .

Refer to the compiler documentation on how to ensure that FP values ​​do not have extended precision.

+2
source

In general, you should be able to - the optimizer should know about the properties of real operations.

However, I would check the hell from the compiler I used.

0
source

Yes. The compiler will not change the order of your calculations in such a block.

0
source

Between optimizing the compiler and running out of turn on the processor, this is almost a guarantee that everything will not be the way you ordered them.

HOWEVER, it is also guaranteed that this will NEVER change the result. C ++ follows the standard order of operations, and all optimizations preserve this behavior.

Bottom line: don't worry about it. Write your C ++ code to be mathematically correct and trust the compiler. If something went wrong, the problem was almost certainly not the compiler.

0
source

If you really need to, I think you can create a noinline function no_reorder (float x) {return x; } and then use it instead of brackets. Obviously, this is not a particularly effective solution.

0
source

According to other answers, you should rely on a compiler that does the right thing - most compilers allow you to compile and verify assembler (use -S for gcc) - you can do this to make sure that you get the expected order of work.

Different optimization levels (in gcc, -O _O2, etc.) allow you to reorder the code (it would be unlikely to affect such a sequential code), but I would advise you to then separate this part of the code into a separate file, so that you can control the level optimization only for calculation.

-1
source

Short answer: the compiler will probably change the order of your calculations, but it will never change the behavior of your program (unless your code uses an expression with undefined behavior: http://blog.regehr.org/archives/213 )

However, you can still influence this behavior by deactivating all compiler optimizations (option β€œ-O0” with gcc). If you still need a compiler to optimize the rest of your code, you can put this function in a separate β€œ.c”, which you can compile with β€œ-O0”. In addition, you can use some hacks. For example, if you alternate your code with calls to an extern function, the compiler may consider it unsafe to reorder your code, because the function may have an unknown side effect. Calling "printf" to print the value of your intermediate results will result in a similar behavior.

In any case, if you do not have a good reason (for example, debugging), you usually do not want to take care of this, and you must trust the compiler.

-1
source

Source: https://habr.com/ru/post/898641/


All Articles