2013-06-17 2 views
5

Я работаю в математической библиотеке, и из-за неотложных проблем с работой с double Я кодирую все сравнения сравнений типа a == b как Math.Abs(a - b) <= epsilon.Как использовать научную нотацию в полях const?

По умолчанию, Я хочу, чтобы мои форматированные строки генерировались с максимальной точностью. То есть, если epsilon - 0.001 Я хочу, чтобы мой формат по умолчанию был N3.

К счастью, я сделал следующее:

public static class Math3D 
{ 
    internal const int ROUND = 3; 
    public const double Epsilon = 1e-ROUND; 
} 

... и я получил ошибку компиляции. По-видимому, это запрещено.

С этим ограничением я не вижу возможности определить как взаимозависимые константы как const. Очевидно, я могу определить Epsilon как поле readonly, но я чувствую, что это так или иначе концептуально неправильно. Не хватает ли я очевидного способа сделать это?

+0

Что такое буквальная ошибка? – rae1

+0

Вы на самом деле делаете математику для 'Epsilon', не создавая значения 0.001. –

+2

Что не так с использованием поля 'readonly'? – xxbbcc

ответ

10

Если вы собираетесь его изменить, вы должны использовать readonly здесь. const действительно нужно использовать для вещей, которые будут никогда изменить, как π. Причина этого - из-за тонкой разницы между const и readonly.

Основная проблема заключается в том, что если вы измените значение const, вы должны перекомпилировать всех зависимых клиентов, которые используют const, в противном случае вы можете shoot yourself in the foot, badly. Так что для значений, которые может изменить, не использовать const, используйте readonly.

Таким образом, если значение никогда изменится, просто использовать const, а затем не беспокоиться об определении Epsilon в терминах ROUND, просто сказать:

internal const int ROUND = 3; 
public const double Epsilon = 1e-3; 

Если вы действительно хотите сделать что вы случайно не изменить один, не изменяя другие, вы могли бы добавить небольшую проверку в конструкторе:

if (Epsilon != Math.Pow(10, -ROUND)) { 
    throw new YouForgotToChangeBothConstVariablesException(); 
} 

можно даже добавить условную компиляцию так тх t только компилируется в отладочных версиях.

Если это собирается изменить, используйте static readonly:

internal readonly int ROUND = 3; 
public static readonly double Epsilon = Math.Pow(10, -ROUND); 

С этим ограничением я не вижу, как я могу определить как interdependant константы, как consts. [...] Не хватает ли я очевидного способа сделать это?

Нет, вам нужно сделать какое-то математику с помощью Math.Pow или Math.Log идти между ROUND и Epsilon и теми, кто не является приемлемым для использования во время компиляции с const.Вы могли бы написать генератор миниатюрного кода, чтобы выплюнуть эти две строки кода на основе одного входного значения, но я действительно сомневаюсь в стоимости времени инвестирования.

+0

Ошибка не вызвана 'const'. – rae1

+0

Ну, это точно точка. Оба константы никогда не изменятся, и именно это я хочу, чтобы код «говорил». В разработке мы могли бы точно настроить стоимость несколько раз, и мне было просто интересно, можем ли мы как-то связать их. Очевидно, что если нет решения, окончательный код будет поставляться с двумя независимыми константами. – InBetween

+0

@InBetween: вы не можете выполнить математику во время компиляции, которую хотите сделать с 'const', чтобы решить проблему, которую вы пытаетесь решить. – jason

2

1e-ROUND, в частности 1e не допустимое целое число. Вы должны сделать что-то вроде,

public static readonly double Epsilon = 
    decimal.Parse(
     string.Format("1E-{0}", ROUND), 
     System.Globalization.NumberStyles.Float); 

Кроме того, обратите внимание на static readonly, так как вы не можете использовать const, когда выражение не будет известно до времени выполнения. В этом случае static readonly будет работать аналогично const.

Если вы предпочитаете не имеете дело с string с, вы всегда можете сделать,

public static readonly double Epsilon = Math.Pow(10, -ROUND); 
+2

... вам «нужно будет» форматировать число в строку, а затем проанализировать его? Назовите меня старомодным, но я нахожу этот огромный концептуальный обход. Для получения номера используйте простой арифметический расчет. –

+0

Я не думаю, что это очень хороший совет. Использование 'Math.Pow()' было бы просто прекрасным и избегало операции синтаксического анализа строки. – xxbbcc

+0

Я хотел сохранить его максимально читаемым. – rae1

1

Вы всегда можете просто жестко закодировать 3. Видя, как вы используете константы, то нет никакого намерения когда-либо изменений значения на что-нибудь, кроме 3, право? Поэтому вам не нужно слишком беспокоиться о СУХОЙ.

public static class Math3D 
{ 
    internal const int ROUND = 3; 
    public const double Epsilon = 1e-3; 
} 

Если вы думаете, вы можете захотеть изменить 3, то const не для вас и ваш вопрос становится спорным.

1

Edit:

Это не является прямым ответом на ваш вопрос, но Вы рассмотрели изменения Round и Epsilon в перезаписываемых областях? Если вы используете их для форматирования/округления, почти гарантировано, что им придется иногда меняться - ни поле const, ни поле readonly не будут работать для этого.

public static class Math3D 
{ 
    internal static int s_Round; 
    internal static double s_Epsilon; 

    static Math3D() 
    { 
     Round = 3; 
    } 

    public static double Epsilon 
    { 
     get 
     { 
      return (s_Epsilon); 
     } 
    } 

    public static int Round 
    { 
     get 
     { 
      return (s_Round); 
     } 
     set 
     { 
      // TODO validate 
      s_Round = value; 
      s_Epsilon = Math.Pow (10, -s_Round); 
     } 
    } 
} 

Это хорошо читаемое решение, которое не сломается, когда вы измените ситуацию в будущем.

+0

+1 Если OP работает в математической библиотеке, имеет смысл настраивать поведение форматирования, поэтому свойство, которое нужно получить и установить ограничение округления, является хорошей идеей. –

+0

Спасибо за образец. Я в основном закончил делать что-то подобное, но я действительно не вижу причин, по которым я хотел бы, чтобы потребители меняли * точность * библиотеки, а «округление» по умолчанию всегда можно было настроить с помощью строк формата, чтобы не было проблема. Таким образом, решение будет состоять из двух полей 'readonly'. – InBetween

+0

@InBetween Я использовал несколько 3D-моделей, где точность могла быть изменена «на лету». В некоторых случаях это очень полезная функция, поэтому я предложил ее. – xxbbcc

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