0

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!
Charlieface
  • 52,284
  • 6
  • 19
  • 43
Matt Arnold
  • 668
  • 2
  • 8
  • 21

1 Answers1

0

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:

private static int Mod(int k, int n) {
    int remainder = k % n;
    return (remainder < 0) ? remainder + n : remainder;
}

// ... in the else branch, you can directly do
return Mod(value - minimumValue, length) + minimumValue;

You also handled value < 0 differently. There is nothing special about a negative value. 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 replaced value < 0 with a check to see if (value - minimumValue) % length is negative.

Sweeper
  • 213,210
  • 22
  • 193
  • 313