在C#中,我如何像google calc那样实现模数呢?

时间:2009-01-26 02:48:23

标签: c# modulo

我有一个代表形状的类。 Shape类有一个名为Angle的属性。我希望此属性的setter自动将值包装到[0,359]范围内。

不幸的是,简单的_Angle = value % 360;仅适用于正数。在C#中,-40 % 360 == -40。 Google calc会做the way I want it。该值应为320。

C#中最优雅的解决方案是什么?

这是我到目前为止最好的方式:

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

修改

谢谢你们,我现在有:

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

..哪个好多了:)

7 个答案:

答案 0 :(得分:9)

虽然这是针对Java的,但Java对模数也有相同的行为。 (即-40 % 360 == -40)。

以下代码应该从[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
    }
}

请注意,当给定角度超过-360时有效。

答案 1 :(得分:4)

虽然您的解决方案可以解决问题,但算法实际上与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

检查google对上一次计算的回复here

该算法在wikipedia上解释,归功于Donald Knuth。

答案 2 :(得分:3)

这应该会给你所需的结果

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

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

答案 3 :(得分:2)

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

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

C代码:

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

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

答案 4 :(得分:1)

// go 'round once

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

答案 5 :(得分:-1)

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

答案 6 :(得分:-1)

如果你的值不会超出范围,你可以做一点循环。

while (value < 0) {
  value = value + 360;
}
while (value > 360) {
  value = value - 360;
}