简体   繁体   English

角度归一化C#

[英]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 ,将进行从intdouble的转换。

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并寻找有效的隐式转换(在这种情况下intdouble之后 ; 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: 另外,值得指出的是,您的构造函数逻辑还存在其他一些问题:

  1. 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符号对minsec的符号进行归一化(难看并可能引起混淆)。

  2. 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 . 除非约定负角必须为负degminsec ,否则计算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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM