5 years, 9 months ago.

Float changing value when copied

It's a C++ question, but hopefully someone on here can help! I have a struct for holding settings (simplified version below):

struct Settings
{
    float gain[6];
    float offset[6];
};

and constants for minimum and maximum values:

const Settings sMin = 
{
    .gain = {0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f},
    .offset = {-200.0f, -200.0f, -200.0f, -200.0f, -200.0f, -200.0f}
};

const Settings sMax = 
{
    .gain = {2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f},
    .offset = {200.0f, 200.0f, 200.0f, 200.0f, 200.0f, 200.0f}
};

When I assign the minimum values to a new Settings, I'm getting a strange issue where the -200.0 is being assigned as -200.000015 so if I then do a comparison to check that the value is within range it fails. Can anyone help me understand why the value in the constant is -200.0, but when I copy the constant it changes to -200.000015. I know I can use memcpy, but it's messy and I'd rather understand why my code isn't working before resorting to this.

Settings s = sMin;

// .....
// Do some stuff with s
// .....

for (int i=0; i<6; i++)
{
    if ((s.gain[i] < sMin[i]) || (s.gain[i] > sMax[i]))
    {
        error("Out of range");
    }
}

2 Answers

5 years, 9 months ago.

My guess is that you're hitting rounding errors.

In a float -200.000015 is 1 count different from -200.000000, if you're doing any calculations at all to end up with your -200 then some sort of least significant bit rounding error may have crept in and caused the difference. This can be an issue when doing >< comparisons with floats.

You could scale the value and then convert to an integer to round it before doing the comparison. Or do the calculations using doubles and only when they are all done convert to a float for the comparison, that should keep the errors insignificant in comparison to the float accuracy.

5 years, 9 months ago.

Hello Tim,

That must be very annoing . Which compiler do you use? I have tested the code below on an LPC1768 board with the mbed ARM online compiler and also with the GNU ARM GCC compiler offline and I was not able to reproduce such error. I also tried GNU GCC on a Windows machine but with the same result.

#include <stdio.h>

struct Settings
{
    float       gain[6];
    const float offset[6];
};

int main()
{
    printf("Starting..\r\n");

    const Settings  sMin =
    {
        .gain = { 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f },
        .offset = { -200.0f, -200.0f, -200.0f, -200.0f, -200.0f, -200.0f }
    };

    const Settings  sMax =
    {
        .gain = { 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f },
        .offset = { 200.0f, 200.0f, 200.0f, 200.0f, 200.0f, 200.0f }
    };
    
    Settings s = sMin;
    
    // .....
    // Do some stuff with s
    // .....
         
    //s.offset[0] = -200.000015 ;   // this would result in compile time error

    for (int i = 0; i < 6; i++)
    {
        if ((s.offset[i] < sMin.offset[i]) || (s.offset[i] > sMax.offset[i]))
            printf("s.offset[%d] = %f", i, s.offset[i]);
    }
            
    printf("\r\n");
    printf("Finished.\r\n");
    
    return 0;
}

To make sure that offset is not changed when doing some stuff with s I would suggest to make it const (as in the code above).

NOTE: By the way, in your snippet you should rather test .offset than .gain.