[英]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
后 ,將進行從int
到double
的轉換。
編譯器不會根據您決定存儲結果的類型為您選擇double
算術。編譯器將根據操作數的類型選擇最佳的運算符重載,在這種情況下,這些操作數均為int
並尋找有效的隱式轉換(在這種情況下int
到double
) 之后 ; 因此,它正在選擇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
精度運算。
另外,值得指出的是,您的構造函數邏輯還存在其他一些問題:
您應該驗證輸入數據; 指定負分鍾或秒數是否有效? IMO似乎不合理。 應僅將deg
設置為負值。 您應該檢查這種情況並采取相應的措施:拋出一個異常(最好),或者根據deg
符號對min
和sec
的符號進行歸一化(難看並可能引起混淆)。
您的seconds
計算對於負角似乎不正確(同樣,這與上一期問題以及您決定實施的任何符號約定有關)。 除非約定負角必須為負deg
, min
和sec
,否則計算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.