atsteich
atsteich

Reputation: 84

Different evaluation when compiling with -O3

The following Code has different behavior, when it is compiled with g++ -O3 .. and without -O3.

I know that updateError is not returning anything, which can lead to undefined behavior. What i don't understand is, that error is set to zero inside the loop if compiled with -O3, and if(error > eps) is evaluated as false, while it is still evaluated as true in the while() statement. .

I have also tried to change it to a do{}while() loop, in that case it worked also with -O3...

#include <stdio.h>


using namespace std;


double updateError(){
    printf("updating Error\n");
}

int main(int argc, char *argv[]){

    double eps = 1.e-10;
    double error = 2*eps;
    int iter = 0;

    while(error > eps){
        error = updateError();
        iter++;
        printf("Error on iteration %i: %.20e\n", iter, error);
        if(error > eps) printf("error bigger\n\n");
        else printf("error smaller\n\n");
        if(iter == 5){
            printf("not converged in 5 iterations!!\n");
            break;
        }
    }
    return 0;
}

Console output with -O3:

updating Error
Error on iteration 1: 0.00000000000000000000e+00
error smaller

updating Error
Error on iteration 2: 0.00000000000000000000e+00
error smaller

updating Error
Error on iteration 3: 0.00000000000000000000e+00
error smaller

updating Error
Error on iteration 4: 0.00000000000000000000e+00
error smaller

updating Error
Error on iteration 5: 0.00000000000000000000e+00
error smaller

not converged in 5 iterations!!

Console output without -O3:

updating Error
Error on iteration 1: 6.92743341769227318242e-310
error smaller

Upvotes: 1

Views: 632

Answers (1)

463035818_is_not_an_ai
463035818_is_not_an_ai

Reputation: 122458

I know that updateError is not returning anything, which can lead to undefined behavior.

There is no "can". Your code has undefined behaviour. Period.

On debug builds the compiler does some stuff extra to enhance the usage of a debugger. This can be things like initializing variables when they actually dont have to be. Such overhead is not done in optimized builds. Anyhow, if you want to understand why you get the results you get you should take a look at the assembly. Just be aware that UB is UB, so you have no guarantee that on the next day you get the same results with the same compiler.

What i don't understand is, that error is set to zero inside the loop if compiled with -O3, and if(error > eps) is evaluated as false, while it is still evaluated as true in the while() statement. .

Note that the code you write is not translated line by line to instructions of your CPU. Compilers are rather clever and apply all kinds of transformations under the as-if rule. As long as the observable behaviour is the same the compiler is allowed to turn your code into something that is quite different from a naive line-by-line translation. If however your code has UB, then it is not valid c++ code and getting differnt output for one and the same variable is not a big surprise.

Upvotes: 11

Related Questions