2009-12-08 3 views
2

Folks,Сравнение двойников в Visual Studio - стандартный способ поймать это?

Даже опытные программисты пишут C# код, как это иногда:

double x = 2.5; 
double y = 3; 
if (x + 0.5 == 3) { 
    // this will never be executed 
} 

В основном, это общеизвестно, что два двухместных (или поплавки) никогда не может быть точно равны друг другу, из-за пути компьютер обрабатывает арифметику с плавающей запятой.

Проблема в том, что все знают об этом, но такой код по-прежнему повсюду. Это так просто пропустить.

Вопросы для Вас:

  • Как вы справляетесь с этим в организации развития?
  • Является ли такая распространенная вещь, что компилятор должен проверять, что все мы должны кричать действительно громко для VS2010, чтобы включить предупреждение о компиляции, если кто-то сравнивает два удваивания/поплавки?

ОБНОВЛЕНИЕ: Люди, спасибо за комментарии. Я хочу пояснить, что я, безусловно, понимаю, что приведенный выше код неверен. Да, вы никогда не хотите, чтобы == сравнить парные и плавающие. Вместо этого вы должны использовать сравнение на основе epsilon. Это очевидно. Реальный вопрос здесь: «Как вы определяете проблему», а не «как вы решаете техническую проблему».

+1

Вы выбрали * другой * плохой пример. Опять же, это всегда будет выполнено. Я предлагаю, чтобы при выборе следующего примера вы попробовали его перед отправкой ... –

+1

(И вы можете удалить ошибочное утверждение о том, что «два двойника никогда не могут быть точно равны друг другу». Если вы собираетесь утверждают, что что-то является «общим знанием» и утверждают, что вы действительно * понимаете все это, стоило бы дважды проверить все, что вы пишете, чтобы убедиться, что это точно. –

+1

Действительно, если числа с плавающей запятой НИКОГДА не были бы точно равными, вероятно, было бы проще, потому что все разработчики знали бы о проблеме. –

ответ

3

значений с плавающей точкой, конечно могут быть равны друг другу, и в случае, если вы дали им всегда будут быть равны. Вы должны почти никогда не сравнивать для равенства с помощью equals, но вам нужно понять, почему - и почему пример, который вы показали, не подходит.

Я не думаю, что это то, о чем обязательно должен сообщать компилятор, но вы можете посмотреть, может ли это что-то такое, что может сделать FxCop. Я не вижу этого в warning list, но он может быть где-то ...

Лично я уверен, что компетентные разработчики смогут обнаружить это в обзоре кода, но это полагается на то, что у вас есть обзор кода для начала. Он также зависит от ваших разработчиков знать, когда использовать double и когда использовать decimal, что-то я нашел часто это не так ...

+1

Я бы добавил +1 к пункту (без каламбура) о десятичном значении - но я поддержал :-) – philsquared

+0

Раньше было правило в FxCop под названием " Избегайте тестирования для равенства с плавающей точкой ", но он был удален некоторое время назад. http://social.msdn.microsoft.com/Forums/is/vstscode/thread/339dc258-2928-476f-92ba-784cb04b7863 – kristianp

2
static int _yes = 0; 
static int _no = 0; 

static void Main(string[] args) 
{ 
    for (int i = 0; i < 1000000; i++) 
    { 
     double x = 1; 
     double y = 2; 
     if (y - 1 == x) 
     { 
      _yes++; 
     } 
     else 
     { 
      _no++; 
     } 
    } 
    Console.WriteLine("Yes: " + _yes); 
    Console.WriteLine("No: " + _no); 
    Console.Read(); 
} 

Выход

Да: +1000000

No: 0

+0

LOL :) 15 символов – Amarghosh

+0

Отлично, отлично, хорошо. Точка стоит. Я отредактирую код. –

2

В нашей организации у нас много финансовых расчетов, и мы не используем float и double для таких задач. Мы используем Decimal в .NET, BigDecimal в Java и Numeric в MSSQL, чтобы избежать ошибок округления.

В данной статье описывается проблема: What Every CS Should Know About floating-Point Arithmetic

+0

Я хорошо знаю решение проблемы. То, что я прошу, - «как это лучше понять», а не «как его решить». –

+0

ОК. Я переписал свой ответ. –

1

Если FxCop или подобный (как говорит Джон) не работает для вас более тяжелой руки подхода может быть взять копию коды - заменить все экземпляры float или double с классом, который вы написали, несколько похожим на System.Double, за исключением того, что вы перегружаете == operator, чтобы создать предупреждение!

Я не знаю, если это возможно на практике, я не пробовал - но дайте нам знать, если вы попробовать :-)

0

Моно Gendarme является FxCop-подобный инструмент. Он имеет правило, называемое AvoidFloatingPointEqualityRule, в категории «Правильность». Вы можете попробовать найти экземпляры этой ошибки в коде. Я не использовал его, но он должен анализировать регулярные DLL .net. Правило FxCop с тем же именем было удалено давно.