Let say I've set a step of 0.1 in my application. So, whatever fp value I get, I just need 1 digit after the comma.
So, 47.93434
must be 47.9
(or at least, the nearest fp representable value).
If I write this:
double value = 47.9;
It correctly "snap" to the nearest fp value it can get, which is:
47.89999999999999857891452847979962825775146484375 // fp value
101111.11100110011001100110011001100110011001100110011 // binary
Now, suppose "I don't write those values", but I got them from a software. And than I need to snap it. I wrote this function:
inline double SnapValue(double value, double step) {
return round(value / step) * step;
}
But it returns these values:
47.900000000000005684341886080801486968994140625 // fp value
101111.11100110011001100110011001100110011001100110100 // binary
which is formally a little far than the first example (its the "next" fp value, 011 + 1
).
How would you get the first value (which is "more correct") for each input value?
Here's the testing code.
NOTE: the step can be different - i.e. step = 0.25
need to snap value around the nearest 0.25 X. Example: a step of 0.25
will return values as 0
, 0.25
, 0.50
, 0.75
, 1.0
, 1.25
and so on. Thus, given an input of 1.30
, it need to wrap to the nearest snapped value - i.e. 1.25
.
You could try to use rational values instead of floating point. The latter are often inaccurate already, so not really an ideal match for a step.
inline double snap(double original, int numerator, int denominator)
{
return round(original * denominator / numerator) * numerator / denominator;
}
Say you want steps of 0.4, then use 2 / 5:
snap(1.7435, 2, 5) = round(4.35875) * 2 / 5 = 4 * 2 / 5 = 1.6 (or what comes closest to it)