Question

I have a class which represents a shape. The Shape class has a property called Angle. I want the setter for this property to automatically wrap the value into the range [0,359].

Unfortunately, a simple _Angle = value % 360; only works for positive numbers. In C#, -40 % 360 == -40. Google calc does it the way I want it. The value should be 320.

What's the most elegant solution in C#?

Here's the best way I've got so far:

     public double Angle {
        get { return _Angle; } 
        set {
            if ( value >= 0 ) {
                _Angle = value % 360;
            }
            else {
                _Angle = value - (360 * ((int)(value / 360) - 1)); 
            }
        }
    }

Edit:

Thanks guys, I now have:

     public double Angle {
        get { return _Angle; } 
        set {
            _Angle = (value % 360) + ((value < 0) ? 360 : 0);
        }
    }

..Which is a lot better :)

Was it helpful?

Solution

Although this is for Java, Java also has the same behavior for modulus. (i.e. -40 % 360 == -40).

The below code should return an answer from [0. 360), regardless of the given angle, positive or negative.

public class Mod
{
    public static int mod(int a, int b)
    {
        if (a < 0)
            return b + (a % b);
        else
            return a % b;
    }

    public static void main(String[] args)
    {
        System.out.println(mod(40, 360));   // 40
        System.out.println(mod(-40, 360));  // 320
        System.out.println(mod(-400, 360)); // 320
    }
}

Note that works when the given angle is past -360.

OTHER TIPS

While your solution works for the problem you have the algorithm is actually not identical to the one used by Google. It differs if you use a negative divisor.

public double GoogleModulo(double value, double divisor)
{
    long q = (long)Math.Floor(value / divisor);
    return value - q * divisor;
}

Console.WriteLine(GoogleModulo(  40,  360)); //   40
Console.WriteLine(GoogleModulo( -40,  360)); //  320
Console.WriteLine(GoogleModulo(-400,  360)); //  320
Console.WriteLine(GoogleModulo(  40, -360)); // -320

Check google's response to the last calculation here.

The algorithm is explained on wikipedia and attributed to Donald Knuth.

This should give you the required results

public double Angle {
    get { return _Angle; }
    set { _Angle = value % 360 + (value % 360 < 0 : 360 : 0); }
}

I am assuming that 360 is degrees and you are trying to find where in the {0, 360} the angle lies.

The mod operation is very slow. If possible replace with bit mask.

coobird's code is pretty good... but is very slow because it is doing a mod operation. If it is possible to scale your data to be within some power of two range, then you can improve the speed by approximately an order of magnitude ( at the very least 2 or 3 times faster ) by using a bit mask.

C code:

#define BIT_MASK (0xFFFF)
if (a < 0) {
    return b + (a & BIT_MASK);
} else {
    return a & BIT_MASK;
}

Feel free to make the #define something that is run time. And feel free to adjust the bit mask to be whatever power of two that you need. Like 0xFFFFFFFF or power of two you decide on implementing.

// go 'round once

set { _Angle = (value + 360) % 360 }

(360 * Math.floor(Math.abs(value) / 360) + value) % 360

If your values aren't going to be wildly out of the range you can do a little loop.

while (value < 0) {
  value = value + 360;
}
while (value > 360) {
  value = value - 360;
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top