Quantcast
Channel: Active questions tagged gcc - Stack Overflow
Viewing all articles
Browse latest Browse all 22313

gcc compiler optimization influences result of floating point comparison

$
0
0

Problem

In using automated CI tests I found some code, which breaks if optimization of gcc is set to -O2. The code should increment a counter if a double value crosses a threshold in either direction.

Workaround

Going down to -O1 or using -ffloat-store option works around the problem.

Example

Here is a small example which shows the same problem. The update() function should return true whenever a sequence of *pNextState * 1e-6 crosses a threshold of 0.03. I used call by reference because the values are part of a large struct in the full code.

The idea behind using < and >= is that if a sequence hits the value exactly, the function should return 1 this time and return 0 the next cycle.

test.h:

extern int update(double * pState, double * pNextState);

test.c:

#include "test.h"

int update(double * pState, double * pNextState_scaled) {
    static double threshold = 0.03;
    double oldState = *pState;
    *pState = *pNextState_scaled * 1e-6;

    return oldState < threshold && *pState >= threshold;
}

main.c:

#include <stdio.h>
#include <stdlib.h>

#include "test.h"

int main(void) {

    double state = 0.01;
    double nextState1 = 20000.0;
    double nextState2 = 30000.0;
    double nextState3 = 40000.0;

    printf("%d\n", update(&state, &nextState1));
    printf("%d\n", update(&state, &nextState2));
    printf("%d\n", update(&state, &nextState3));

    return EXIT_SUCCESS;
}

Using gcc with at least -O2 the output is:

0
0
0

Using gcc with -O1, -O0 or -ffloat-store produces the desired output

0
1
0

As i understand the problem from debugging a problem arises if the compiler optimizes out the local variable oldstate on stack and instead compares against an intermediate result in an floting point register with higher precision (80bit) and the value *pState is a tiny bit smaller than the threshold. If the value for comparison is stored in 64bit precision, the logic can't miss crossing the threshold. Because of the multiplication by 1e-6 the result is probably stored in an floating point register.

Would you consider this a gcc bug? clang does not show the problem.

I am using gcc version 9.2.0 on an Intel Core i5, Windows and msys2.

Update

It is clear to me that floating point comparison is not exact and i would consider the following result as valid:

0
0
1

The idea was that, if (*pState >= threshold) == false in one cycle then comparing the same value (oldstate = *pState) against the same threshold in a subsequent call (*pState < threshold) has to be true.


Viewing all articles
Browse latest Browse all 22313

Latest Images

Trending Articles



Latest Images

<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>