In C#, how do I implement modulus like google calc does?

[亡魂溺海] 提交于 2019-12-23 09:05:11

问题


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

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!