This question refers to this one, but applying to floating point numbers too.
In short, if count reaches min or max bound it should wrap to opposite bound taking into account remainder of step value overflow (for instance if bounds are 0 ... 10.5
, value
is 3 and step
is -7.5). Also we should handle case when step
value is greater than range
value.
Ranges may be arbitrary (negative, positive or mixed) but taking into account given asserts.
So far I have this method which works for integers, but gives wrong result for doubles whenever step
is fractional.
Also not sure we should use epsilon approach here while comparing doubles.
Question is how to implement this method properly for fractional values.
#include <iostream>
#include <cmath>
#include <assert.h>
double
countInRange(const double step, const double value, const double minValue, const double maxValue)
{
assert(minValue < maxValue);
assert(value >= minValue && value <= maxValue);
auto range = maxValue - minValue + 1;
assert(fabs(step) <= range);
auto result = value + step;
if (result < minValue) {
result += range;
} else if (result > maxValue) {
result -= range;
}
return result;
}
int main()
{
double v = 358;
printf("increment\n");
for (int i = 0; i < 10; i++) {
v = countInRange(0.5, v, 0, 359.5);
printf("%f\n", v);
}
printf("decrement\n");
v = 2;
for (int i = 0; i < 10; i++) {
v = countInRange(-0.5, v, 0, 359.5);
printf("%f\n", v);
}
}
Edit
So I ended up with two methods for different interval logics, the first one taken from answer of Superlokkus, they may not cover all cases, but for now it's enough, thanks to all the commenters
/**
* Wraps to minValue or maxValue plus step using half-open interval logic
*/
double
countInRange(const double step, const double value, const double minValue, const double maxValue)
{
assert(minValue < maxValue);
assert(value >= minValue && value <= maxValue);
auto range = maxValue - minValue + 1;
assert(fabs(step) <= range);
auto result = value + step;
if (result < minValue) {
result = maxValue - abs(minValue - result);
} else if (result > maxValue) {
result = minValue + (result - maxValue);
}
return result;
}
/**
* Wraps to minValue or maxValue using closed interval logic
*/
double
countInRange(const int step, const double value, const double minValue, const double maxValue)
{
assert(minValue < maxValue);
assert(value >= minValue && value <= maxValue);
auto range = maxValue - minValue + 1;
assert(abs(step) <= range);
auto result = value + step;
if (result < minValue) {
result += range;
} else if (result > maxValue) {
result -= range;
}
return result;
}