0

Problem encoutered

In my program (C++ with Qt), I need to store a float value (let's call it step) which is divisible by 0.15. It is required to store this value as an integer which is the result of the division of step by 0.15. This did the trick:

int storedValue;
[...]
storedValue = step / 0.15;

Unfortunately, for reasons I ignore, some step values (such as 300.15 or 300.30) aren't divided correctly: when step has the value 300.15, storedValue is 2000 instead of being 2001. Similarly, 300.30 as a step gives storedValue a value of 2001. Then, 300.45 would correctly give storedValue 2003, and so on.

I have no idea why 300.15 and 300.30 have this bug, nor if there are any other values that trigger this bug.

Solutions tried

I think the C++ conversion from float to int is the issue, since I checked the result of the division as a float and it is correct, so I made a float value to hold the result of the division, and use storedValue = static_cast<int>(floatResult), hoping it would make for a better conversion. And, weirdly enough, 300.15 has now the correct storedValue of 2001, but the bug still happen with 300.30, giving the same storedValue of 2001.

The current solution I have tried, but am unhappy with since it does not understand the problem and is not robust, is the following:

float floatResult = step / 0.15;
int storedValue = static_cast<int>(floatResult);
float verification = static_cast<float>(storedValue);

// If storedValue is false, verification will be different of floatResult
if (floatResult != verification) {
    storedValue = storedValue + 1;
    verification = static_cast<float>(storedValue);
    // Case I have never experienced, but since I can't understand the problem, I need to be careful
    if (floatResult != verification) {
        storedValue = storedValued - 2;
        verification = static_cast<float>(storedValue);
        if (floatResult != verification) {
            // Throw error
        }
    }
}

I found nothing relevant on the matter, since I am sure the result of this division is an integer (the user can't input a step not divisible by 0.15), so I don't see how precision matters here. Do someone have an idea about why this problem happens ? And/or how to improve my solution ?

Fareanor
  • 5,900
  • 2
  • 11
  • 37
superpg
  • 253
  • 2
  • 9
  • Related: https://stackoverflow.com/questions/588004/is-floating-point-math-broken – Damien Jan 07 '20 at 10:12
  • 2
    You may try to use `= std::lround (step/0.15)` – Damien Jan 07 '20 at 10:15
  • 1
    On that note, you can see this by checking the values in a debugger or printing. e.g. 300.149994, 0.150000006 and 2000.99988. Conversion from float to int then *rounds down*. – Fire Lancer Jan 07 '20 at 10:15
  • @Damien I should have said, I tried using `std::round`, but it looks like my C++ version is not recent enough. – superpg Jan 07 '20 at 10:23
  • `std::lround` is available since C++11. Which compiler are use using? Did you use the C++11 flag? Did you include ``? – Damien Jan 07 '20 at 10:26
  • If really `std::lround` is not available, and if `step` is positive, then you can try `static_cast(step/0.15 + 0.5)` for example – Damien Jan 07 '20 at 10:31
  • @Damien `step` can be negative. I can use `std::floor` being careful about those negatives values. – superpg Jan 07 '20 at 10:46
  • It occured to me, since it is a Qt project, I can use the `qRound()` method instead of `std::round`. I use it to round the result of the division. Case solved. – superpg Jan 07 '20 at 14:49

0 Answers0