在C#中,我如何实现像谷歌计算一样的模数呢?

时间:2022-09-02 14:48:12

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].

我有一个代表形状的类。 Shape类有一个名为Angle的属性。我希望此属性的setter自动将值包装到范围[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.

不幸的是,一个简单的_Angle = value%360;仅适用于正数。在C#中,-40%360 == -40。谷歌calc以我想要的方式做到了。值应为320。

What's the most elegant solution in C#?

什么是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 :)

..哪个好多了:)

7 个解决方案

#1


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

虽然这适用于Java,但Java也具有相同的模数行为。 (即-40%360 == - 40)。

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

下面的代码应该从[0。 360),无论给定角度,正面还是负面。

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.

请注意,当给定角度超过-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.

虽然您的解决方案可以解决问题,但算法实际上与Google使用的算法不同。如果使用负除数则不同。

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.

我假设360度是度,你试图找到{0,360}角度所在的位置。

#4


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

mod操作非常慢。如果可能,用位掩码替换。

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.

coobird的代码非常好......但是因为它正在进行mod操作而非常慢。如果可以将数据缩放到两个范围内的某个幂,则可以使用位掩码将速度提高大约一个数量级(至少快2或3倍)。

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.

随意将#define变成运行时的东西。并随意调整位掩码,使其成为您需要的两种功率。像0xFFFFFFFF或2的幂,你决定实施。

#5


// go 'round once

//一圈一圈

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

设置{_Angle =(值+ 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;
}

#1


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

虽然这适用于Java,但Java也具有相同的模数行为。 (即-40%360 == - 40)。

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

下面的代码应该从[0。 360),无论给定角度,正面还是负面。

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.

请注意,当给定角度超过-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.

虽然您的解决方案可以解决问题,但算法实际上与Google使用的算法不同。如果使用负除数则不同。

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.

我假设360度是度,你试图找到{0,360}角度所在的位置。

#4


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

mod操作非常慢。如果可能,用位掩码替换。

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.

coobird的代码非常好......但是因为它正在进行mod操作而非常慢。如果可以将数据缩放到两个范围内的某个幂,则可以使用位掩码将速度提高大约一个数量级(至少快2或3倍)。

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.

随意将#define变成运行时的东西。并随意调整位掩码,使其成为您需要的两种功率。像0xFFFFFFFF或2的幂,你决定实施。

#5


// go 'round once

//一圈一圈

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

设置{_Angle =(值+ 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;
}