问题
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 :)
回答1:
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.
回答2:
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.
回答3:
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.
回答4:
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.
回答5:
// go 'round once
set { _Angle = (value + 360) % 360 }
回答6:
(360 * Math.floor(Math.abs(value) / 360) + value) % 360
回答7:
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;
}
来源:https://stackoverflow.com/questions/478721/in-c-how-do-i-implement-modulus-like-google-calc-does