Search code examples
c#algorithmmathintmodulo

Circulating integer


I need to write an integer that "circulates" between a minimum and maximum value. If the maximum value is reached and you add 1, it jumps to the minimum value. If you subtract 1 from the minimum value you reach the maxValue.


Example:
minValue = 2;
maxValue = 10;

leads to: ... 2,3,4,...9,10,2,3,...


I figured out the addition algorithm, but I'm stuck with the subtraction. Addition looks like this:

public static circularInt operator +(circularInt a, int b)
{
    int sum = a.value + b;        
    int circularValue = ((sum - a.minValue) % (a.maxValue + 1 - a.minValue)) + a.minValue;

    return new circularInt(circularValue, a.minValue, a.maxValue);
}

Basically the algorithm can be broken down to "newValue % range". All the +- minValue is just to eliminate it from the calculation, and add it later on again.

Is there a known algorithm for this? If not, do you have an idea how the subtraction algorithm might look like?


Solution

  • Start by applying the modulo to b and subtracting the minimum from a.value

    int range = a.maxValue + 1 - a.minValue;
    b %= range;
    int value = a.value - a.minValue;
    

    Allowing for negative values, b will now be greater than -range and less than range.

    For addition, add b and the range to the value, and apply the modulo. Adding the range is necessary when b is a negative number. Adding a negative number is the same as subtracting a positive number.

    int result = (value+range+b) % range;
    

    For subtraction, add the range to the value before subtracting b, and apply the modulo. This works because (value+range) % range == value so adding the range doesn't change the final result, but it does keep the intermediate result from going negative.

    int result = (value+range-b) % range;
    

    Finish by adding the minimum back in

    int circularValue = result + a.minValue;
    

    Here's the final code, courtesy of @Meister der Magie

    Addition:

    public static circularInt operator +(circularInt a, int b)
    {
        int range = (a.maxValue + 1 - a.minValue);
        b %= range;
        int value = a.value - a.minValue;
    
        int additionResult = (value+range+b) % range;
    
        int circularValue = additionResult + a.minValue;
        return new circularInt(circularValue, a.minValue, a.maxValue);
    }
    

    Subtraction:

    public static circularInt operator -(circularInt a, int b)
    {
        int range = (a.maxValue + 1 - a.minValue);
        b %= range;
        int value = a.value - a.minValue;
    
        int subtractionResult = (value+range-b) % range;
    
        int circularValue = subtractionResult + a.minValue;
        return new circularInt(circularValue, a.minValue, a.maxValue);
    }