簡體   English   中英

角度歸一化C#

[英]Angle Normalization C#

我有一個具有此構造函數的Angle類

public  Angle(int deg, //  Degrees, minutes, seconds
                  int min, //    (Signs should agree
                  int sec) //       for conventional notation.)
{
   /* //Bug degree normalization 
    while (deg <= -180) deg += 360;
    while (deg > Math.PI) deg -= 360;
    //correction end */

    double seconds = sec + 60 * (min + 60 * deg);
    value = seconds * Math.PI / 648000.0;
    normalize(); 
}

我有這些值來測試該構造函數

  int[] degrees = { 0, 180, -180, Int32.MinValue / 60, 120+180*200000};
        int[] minutes = { 0, 0, 0, 0,56};
        int[] seconds = { 0, 0, 0, 0,10};
        Console.WriteLine("Testing constructor Angle(int deg, int min)");
        for (int i = 0; i < degrees.Length; i++)
        {

            p = new Angle(degrees[i], minutes[i], seconds[i]);
            Console.WriteLine("p = " + p);
        }
        /*Testing constructor Angle(int deg, int min)
        p = 0°0'0"
        p = 180°0'0"
        p = 180°0'0"
        p = 0°8'0" incorrect output 
        p = -73°11'50"  incorrect output expected  120 56 10 
         */

我不明白為什么這里有bug? 為什么他們使用Int32.MinValue除以60和120 + 180 * 200000作為這種格式?

構造函數中的注釋是對代碼的更正

更新 :添加了normalize()代碼

//  For compatibility with the math libraries and other software
//  range is (-pi,pi] not [0,2pi), enforced by the following function:  

void normalize()
{
    double twoPi = Math.PI + Math.PI;          
    while (value <= -Math.PI) value += twoPi;
    while (value >   Math.PI) value -= twoPi;
}  
    //  For compatibility with the math libraries and other software
//  range is (-pi,pi] not [0,2pi), enforced by the following function:  

void normalize()
{double twoPi = Math.PI + Math.PI;          
    while (value <= -Math.PI) value += twoPi;
    while (value >   Math.PI) value -= twoPi;
}     

這是我的規范化功能

問題出在這段代碼中:

double seconds = sec + 60 * (min + 60 * deg);

盡管您將seconds存儲為double ,但是在將sec + 60 * (min + 60 * deg)計算int ,將進行從intdouble的轉換。

編譯器不會根據您決定存儲結果的類型為您選擇double算術。編譯器將根據操作數類型選擇最佳的運算符重載,在這種情況下,這些操作數均為int並尋找有效的隱式轉換(在這種情況下intdouble之后 ; 因此,它正在選擇int算術,並且該操作將在最后兩個測試用例中溢出:

Int32.MinValue / 60 * 60 * 60 = Int32.MinValue * 60 < Int32.MinValue將會溢出。

120 + 180 * 200000 * 60 * 60 > Int32.MaxValue也會溢出。

您對這兩種情況的預期結果可能沒有考慮此行為。

為了解決此問題,請將您的代碼更改為:

double seconds = sec + 60 * (min + 60f * deg);

60顯式設置為double精度型常量( 60f )將強制編譯器將所有運算解析為double精度運算。

另外,值得指出的是,您的構造函數邏輯還存在其他一些問題:

  1. 您應該驗證輸入數據; 指定負分鍾或秒數是否有效? IMO似乎不合理。 應僅將deg設置為負值。 您應該檢查這種情況並采取相應的措施:拋出一個異常(最好),或者根據deg符號對minsec的符號進行歸一化(難看並可能引起混淆)。

  2. 您的seconds計算對於負角似乎不正確(同樣,這與上一期問題以及您決定實施的任何符號約定有關)。 除非約定負角必須為負degminsec ,否則計算seconds是錯誤的,因為無論deg的符號如何,您總是要加上分和秒項。

更新在您有機會對其進行測試之前,我錯過了代碼中的另一個問題。 您的一些測試用例失敗了,因為double沒有足夠的分辨率。 我認為您的代碼需要進行一些重大的重構; normalize()應該首先被調用。 這樣,您將始終管理不會導致溢出或精度損失的緊密邊界值。

這就是我要做的方式:

 public Angle(int deg, int min, int sec)
 {
     //Omitting input values check.

     double seconds = sec + 60 * (min + 60 * normalize(deg));
     value = seconds * Math.PI / 648000f;
 }

 private int normalize(int deg)
 {
     int normalizedDeg = deg % 360;

     if (normalizedDeg <= -180)
         normalizedDeg += 360;
     else if (normalizedDeg > 180)
         normalizedDeg -= 360;

     return normalizedDeg;
 }

他們使用非常大的負數和正數來確保歸一化將角度正確限制在[-180,180]度范圍內。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM