7

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

不幸的是,一个简单的_Angle = value % 360;只适用于正数。在 C# 中,-40 % 360 == -40. Google calc 会按照我想要的方式进行。该值应为 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);
        }
    }

..哪个更好:)

4

7 回答 7

10

尽管这适用于 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 时有效。

于 2009-01-26T03:04:56.020 回答
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 对最后一次计算的响应。

该算法在wikipedia上进行了解释,并归因于 Donald Knuth。

于 2009-02-12T14:13:34.217 回答
3

这应该会给你所需的结果

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

我假设 360 是度数,而您正试图找出角度在 {0, 360} 中的位置。

于 2009-01-26T03:10:31.343 回答
2

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

coobird 的代码很不错……但是很慢,因为它正在执行 mod 操作。如果可以将数据缩放到 2 的某个幂范围内,那么您可以通过使用位掩码将速度提高大约一个数量级(至少快 2 或 3 倍)。

C代码:

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

随意将#define 设置为运行时。并随意将位掩码调整为您需要的任何二的幂。就像您决定实施的 0xFFFFFFFF 或 2 的幂一样。

于 2009-04-06T19:47:45.377 回答
1

// go 'round once

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

于 2009-01-26T02:58:10.137 回答
-1
(360 * Math.floor(Math.abs(value) / 360) + value) % 360
于 2009-01-26T02:59:07.513 回答
-1

如果您的值不会超出范围,您可以做一个小循环。

while (value < 0) {
  value = value + 360;
}
while (value > 360) {
  value = value - 360;
}
于 2009-01-26T03:02:35.120 回答