2009-01-26 15 views
6

我有一個代表形狀的類。 Shape類有一個名爲Angle的屬性。我希望此屬性的setter自動將值包裝到範圍[0,359]中。在C#中,我如何實現像谷歌calc一樣的模數?

不幸的是,一個簡單的_Angle = value % 360;只適用於正數。在C#中,-40 % 360 == -40。谷歌計算公司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); 
     } 
    } 

..這是一個很大更好:)

+1

我強烈不鼓勵使用mod操作,因爲硬件mod/division很慢。如果您能夠將數據擴展爲2的冪,則可以使用利用位掩碼的更好的解決方案。 – 2009-04-06 20:10:49

+0

@TrevorBoydSmith:C#編譯器不允許在整數情況下優化除法和位模運算嗎?在浮動值的情況下,您可以優化位操作嗎? – 2012-05-02 14:29:59

回答

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時工作。

+0

哇這太複雜了,你真的不需要額外的if語句。 – 2009-01-26 03:11:19

1

// go 'round once

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

+0

我想到了,但如果一個小於-360的值被傳遞了呢? – Blorgbeard 2009-01-26 03:03:35

+0

是的,我在這裏假設角度在每次更新時都被標準化。 – 2009-01-28 20:41:12

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

如果你的值不會超出範圍,你可以做一個小循環。

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

這應該給你所需要的結果

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

我假設360度,你正在努力尋找在{0,} 360的角度在哪裏。

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 

檢查谷歌對上次計算的迴應here

算法在wikipedia上解釋並歸因於Donald Knuth。

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或兩個權力,你決定實施。

相關問題