You can wrap it using two modulo operations , which are still equivalent to division . I do not think there is a more efficient way to do this without suggesting something about x .
x = (((x - x_min) % (x_max - x_min)) + (x_max - x_min)) % (x_max - x_min) + x_min;
The additional sum and module by the formula are intended to handle cases when x is actually less than x_min and the module may turn out to be negative. Or you can do it with if and one modular unit:
if (x < x_min) x = x_max - (x_min - x) % (x_max - x_min); else x = x_min + (x - x_min) % (x_max - x_min);
If only x is close to x_min and x_max and is accessible with very few sums or subtractions (think also about spreading errors), I think the module is your only available method.
No division
Bearing in mind that error propagation can become relevant, we can do this with a loop:
d = x_max - x_min; if (abs(d) < MINIMUM_PRECISION) { return x_min; // Actually a divide by zero error :-) } while (x < x_min) { x += d; } while (x > x_max) { x -= d; }
Probability Note
Using modular arithmetic has some statistical implications (floating point arithmetic will also have other meanings).
For example, suppose we wrap a random value between 0 and 5 that is included (for example, the result of a hex dice game) in the range [0,1] (that is, tossing a coin). Then
0 -> 0 1 -> 1 2 -> 0 3 -> 1 4 -> 0 5 -> 1
if the input has a flat spectrum, i.e. each number (0-5) has a probability of 1/6, the output will also be flat, and each element will have a probability of 3/6 = 50%.
But if we had a five-sided dice (0-4), or if we had a random number from 0 to 32767 and wanted to reduce it in the range (0, 99) to get a percentage, the result would not be flat, and some the numbers will be slightly (or not so little) more likely than others. In the case of a five-sided dice game with a throw, the coins of the head against the tails would be 60% -40%. In the case of 32767 percent, a percentage below 67 will be CEIL (32767/100) / FLOOR (32767/100) = 0.3% more likely than the rest.
(To see this more clearly, consider the number from β00000β to β32767β: after every 328 throws, the first three digits of the number will be β327.β When this happens, the last two digits can go only from β00β to β67β, they cannot be from β68β to β99β because 32768 is out of range, so the numbers from 00 to 67 are slightly less likely.
Thus, if someone wanted to get a flat output, he would have to make sure that (max-min) is a divisor of the input range. In the case of 32767 and 100, the input range should be cut to the nearest hundred (minus one), 32699, so that (0-32699) contains 32700 results. Whenever the input was> = 32700, the input function would have to be called again to get a new value:
function reduced() { #ifdef RECURSIVE int x = get_random(); if (x > MAX_ALLOWED) { return reduced(); // Retry } #else for (;;) { int x = get_random(); int d = x_max - x_min; if (x > MAX_ALLOWED) { continue; // Retry } return x_min + ( ( (x - x_min) % d ) + d ) % d; } #endif
When the value of (INPUTRANGE% OUTPUTRANGE) / (INPUTRANGE) is significant, the overhead can be significant (for example, about twice as many calls are required to reduce from 0-197 to 0-99).
If the input range is less than the output (for example, we have a coin flipper and want to roll the dice), multiply (do not add) the Horner algorithm as many times as needed to get a larger input range. The coin spread has a range of 2, CEIL (LN (OUTPUTRANGE) / LN (INPUTRANGE)) is 3, so we need three multiplications:
for (;;) { x = ( flip() * 2 + flip() ) * 2 + flip(); if (x < 6) { break; } }
or get a number from 122 to 221 (range = 100) from a roll of dice:
for (;;) { // ROUNDS = 1 + FLOOR(LN(OUTPUTRANGE)/LN(INPUTRANGE)) and can be hardwired // INPUTRANGE is 6 // x = 0; for (i = 0; i < ROUNDS; i++) { x = 6*x + dice(); } x = dice() + 6 * ( dice() + 6 * ( dice() /* + 6*... */ ) ); if (x < 200) { break; } } // x is now 0..199, x/2 is 0..99 y = 122 + x/2;