[英]Angle Normalization C#
I have an Angle class that has this constructor 我有一个具有此构造函数的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();
}
and I have these values for testing that constructor 我有这些值来测试该构造函数
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
*/
I do not understand why there is a bug here ? 我不明白为什么这里有bug? and why did they use divide Int32.MinValue by 60 and 120+180*200000 as this format ?
为什么他们使用Int32.MinValue除以60和120 + 180 * 200000作为这种格式?
the comments in the constructor is a correction for the code 构造函数中的注释是对代码的更正
UPDATE : Added the code of normalize()
更新 :添加了
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;
}
This is the normalize function that I have 这是我的规范化功能
The problem is in this piece of code: 问题出在这段代码中:
double seconds = sec + 60 * (min + 60 * deg);
Although you are storing seconds
as a double
, the conversion from int
to double
is taking place after sec + 60 * (min + 60 * deg)
is computed as an int
. 尽管您将
seconds
存储为double
,但是在将sec + 60 * (min + 60 * deg)
计算为int
后 ,将进行从int
到double
的转换。
The compiler will not choose double
arithmetics for you based on the type you decide to store the result in. The compiler will choose the best operator overload based on the types of the operands which in this case are all int
and look for a valid implicit conversion (in this case int
to double
) afterwards ; 编译器不会根据您决定存储结果的类型为您选择
double
算术。编译器将根据操作数的类型选择最佳的运算符重载,在这种情况下,这些操作数均为int
并寻找有效的隐式转换(在这种情况下int
到double
) 之后 ; therefore it is choosing int
arithmetics and the operation will overflow in the last two test cases: 因此,它正在选择
int
算术,并且该操作将在最后两个测试用例中溢出:
Int32.MinValue / 60 * 60 * 60
= Int32.MinValue * 60
< Int32.MinValue
which will overflow. Int32.MinValue / 60 * 60 * 60
= Int32.MinValue * 60
< Int32.MinValue
将会溢出。
120 + 180 * 200000 * 60 * 60
> Int32.MaxValue
which will also overflow. 120 + 180 * 200000 * 60 * 60
> Int32.MaxValue
也会溢出。
Your expected results for these two cases are probably not considering this behavior. 您对这两种情况的预期结果可能没有考虑此行为。
In order to solve this issue, change your code to: 为了解决此问题,请将您的代码更改为:
double seconds = sec + 60 * (min + 60f * deg);
Explicitly setting 60
to a double
typed literal constant ( 60f
) will force the compiler to resolve all operations to double
arithmetics. 将
60
显式设置为double
精度型常量( 60f
)将强制编译器将所有运算解析为double
精度运算。
Also, it is worth pointing out that your constructor logic has some other issues: 另外,值得指出的是,您的构造函数逻辑还存在其他一些问题:
You should be validating the input data; 您应该验证输入数据; should it be valid to specify negative minutes or seconds?
指定负分钟或秒数是否有效? IMO that doesn't seem reasonable.
IMO似乎不合理。 Only
deg
should be allowed to have a negative value. 应仅将
deg
设置为负值。 You should check for this condition and act accordingly: throw an exception (preferable) or normalize sign of min
and sec
based on the sign of deg
(ugly and potentially confusing). 您应该检查这种情况并采取相应的措施:抛出一个异常(最好),或者根据
deg
符号对min
和sec
的符号进行归一化(难看并可能引起混淆)。
Your seconds
calculation doesn't seem to be correct for negative angles (again, this is tied to the previous issue and whatever sign convention you have decided to implement). 您的
seconds
计算对于负角似乎不正确(同样,这与上一期问题以及您决定实施的任何符号约定有关)。 Unless the convention is that negative angles must have negative deg
, min
and sec
, the way you are computing seconds
is wrong because you are always adding the minutes and seconds terms no matter the sign of deg
. 除非约定负角必须为负
deg
, min
和sec
,否则计算seconds
是错误的,因为无论deg
的符号如何,您总是要加上分和秒项。
UPDATE There is one more issue in your code that I missed until I had the chance to test it. 更新在您有机会对其进行测试之前,我错过了代码中的另一个问题。 Some of your test cases are failing because
double
doesn't have enough resolution. 您的一些测试用例失败了,因为
double
没有足够的分辨率。 I think your code needs some major refactoring; 我认为您的代码需要进行一些重大的重构;
normalize()
should be called first. normalize()
应该首先被调用。 This way you will always be managing tightly bounded values that can not cause overflows or precision loss. 这样,您将始终管理不会导致溢出或精度损失的紧密边界值。
This is the way I would do it: 这就是我要做的方式:
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.