I'm trying to create a function to underflow a number back up or overflow a number back down into a specified range mathematically. I think I was able to get this to work when the numbers are all positive (taking out Math.Abs (used to positivify negative numbers)) but ranges which go negative or negative values fail. I want to solve this with Maths but can't figure out what I'm doing wrong!
This is my current implementation of the failing function:
/// <summary>
/// Wraps a value within the specified range, overflowing or underflowing as necessary.
/// </summary>
/// <param name="value">The number to wrap.</param>
/// <param name="minimumValue">The minimum value in the range.</param>
/// <param name="length">The number of values in the range to wrap across.</param>
/// <returns>The <paramref name="value"/> wrapped to the specified range.</returns>
/// <exception cref="ArgumentException">Thrown if <paramref name="length"/> is <c>0</c>.</exception>
public static int Wrap(this int value, int minimumValue, int length)
{
if (length == 0)
throw new ArgumentException($"{nameof(length)} must not be 0 in order to produce a range to wrap across.");
else
{
var absoluteModulus = System.Math.Abs((value - minimumValue) % length);
return (value < 0 ? length - absoluteModulus : absoluteModulus) + minimumValue;
}
}
Here's some test data and results for the current implementation:
| value | minimumValue | length | expected | actual | Comment |
|---|---|---|---|---|---|
| 128 | 256 | 128 | 256 | 256 | Pass |
| 255 | 256 | 256 | 511 | 257 | Modulo is underflowing backwards! |
| -3 | 1 | 2 | 1 | 3 | Somehow underflowing out of range! |
| -4 | 0 | 2 | 0 | 2 | Again, underflowing out of range! |
| 63 | 128 | 384 | 447 | 193 | 128 - 63 == 65, 384 - 65 == 319, 319 + 128 == 447, not 193‼ |
| 300 | 100 | 200 | 100 | 100 | This overflow works! |
You seem to be aware that
%is the remainder operation, not modulus (as in modular arithmetic), but simply getting the absolute value of the modulus is not correct. You should use one of the answers here. For example:You also handled
value < 0differently. There is nothing special about a negativevalue. What is special here, is a negative remainder, which is a value that will never be produced by the modulus operation. Your code would have worked too if you replacedvalue < 0with a check to see if(value - minimumValue) % lengthis negative.