2014-10-11 2 views
0

У меня есть класс Angle, который имеет этот конструкторУгол Нормализация C#

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 
     */ 

Я не понимаю, почему есть ошибка здесь? и почему они использовали divide Int32.MinValue на 60 и 120 + 180 * 200000 в качестве этого формата?

комментарии в конструкторе коррекции для кода

UPDATE: Добавлен код 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; 
} 
+1

Что именно вы спрашиваете? Вы спрашиваете, как обеспечить угол между 0 и 2pi или вы спрашиваете, как ваш выход был достигнут? Если это последний, вам нужно будет показать вашу функцию normalize(). Одной из распространенных проблем с этим типом проблемы является то, что вы учитываете только первые два вращения и не более того. Вы должны убедиться, что ваша функция normalize() учитывает углы больше 4pi. – brcpar

+0

while (deg> Math.PI) deg - = 360; эта строка не имеет смысла ... Вы, конечно, имеете в виду deg> 180 – tolanj

+0

Использование цикла while, чтобы обернуть значения, является идеей _bad_. – ja72

ответ

1

Проблема в этом фрагменте кода:

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

Хотя вы храните seconds как double, преобразование int в double происходит послеsec + 60 * (min + 60 * deg) рассчитано как int.

Компилятор не будет выбирать 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 арифметики.

Кроме того, стоит отметить, что ваш конструктор логики имеет некоторые другие вопросы:

  1. Вы должны быть проверки входных данных; следует ли указывать отрицательные минуты или секунды? ИМО, которая не кажется разумной. Только deg должно иметь отрицательное значение. Вы должны проверить это условие и действовать соответственно: выбросить исключение (предпочтительно) или нормализовать знак min и sec на основании знака deg (уродливые и потенциально запутывающие).

  2. Ваш seconds расчет не подходит для отрицательных углов (опять же, это связано с предыдущей проблемой и любым соглашением о знаках, которое вы решили реализовать). Если соглашением является то, что отрицательные углы должны иметь отрицательные deg, min и sec, то, как вы вычисляете seconds, неправильно, потому что вы всегда добавляете минуты и секунды, независимо от знака deg.

UPDATE Существует еще одна проблема в вашем коде, который я пропустил, пока я не имел возможности проверить его. Некоторые из ваших тестовых случаев терпят неудачу, потому что 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; 
} 
+0

, когда я попытался сменить значение на две секунды = сек + 60 * (мин + 60f * град) .. это дает мне окончательный результат для Int32.MinValue/60 как 167 ° 59'0 ".. почему он меняет мин до 59. Я думаю, что правильный выход должен быть 166 0 0 .. правильно, но он дает мне ожидаемый выход для последнего значения, которое составляет 120 ° 56'10 ". – Concealed

+0

@ Jayda'aAlidrisi См. обновление к моему ответу. – InBetween

-1

Они используют очень большие отрицательные и положительные числа, чтобы убедиться, что нормализационные колпачки соответствуют углам [-180, 180] градусов должным образом.

0
// 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; 
}  

Это функция нормализуют, что у меня есть

+0

Не отвечайте на свой вопрос, чтобы предоставить дополнительную информацию. Измените свой вопрос, добавив новую информацию, и укажите ее ** с уведомлением ** UPDATE **, в котором описывается новая информация и как она имеет значение. – InBetween

Смежные вопросы