Правильный способ сравнить System.Double к '0' (число, int?) - PullRequest
80 голосов
/ 06 июля 2011

Извините, это может быть простой глупый вопрос, но мне нужно знать, чтобы быть уверенным.

У меня есть это if выражение,

void Foo()
{
    System.Double something = GetSomething();
    if (something == 0) //Comparison of floating point numbers with equality 
                     // operator. Possible loss of precision while rounding value
        {}
}

Это выражение равно

void Foo()
{
    System.Double something = GetSomething();
    if (something < 1)
        {}
}

?Потому что тогда у меня могут возникнуть проблемы с вводом if, например, со значением 0,9.

Ответы [ 6 ]

100 голосов
/ 06 июля 2011

Ну, как близко вам нужно, чтобы значение было 0?Если вы выполните много операций с плавающей запятой, которые с «бесконечной точностью» могут привести к 0, вы можете получить результат, «очень близкий» к 0.

Как правило, в этой ситуации вы хотите предоставить некоторыесвоего рода эпсилон, и убедитесь, что результат находится в пределах этого эпсилона:

if (Math.Abs(something) < 0.001)

Эпсилон, который вы должны использовать, зависит от приложения - это зависит от того, что вы делаете.

Конечно, если результат должен быть точно ноль, тогда простая проверка на равенство подойдет.

29 голосов
/ 27 июля 2015

Если something был назначен из результата операции, отличной от something = 0, то лучше использовать:

if(Math.Abs(something) < Double.Epsilon)
{
//do something
}

Редактировать : этот код неверен.Эпсилон - наименьшее число, но не совсем ноль.Если вы хотите сравнить число с другим числом, вам нужно подумать о том, что является допустимым отклонением.Допустим, что за пределами .00001 вас не волнует.Это номер, который вы бы использовали.Значение зависит от домена.Тем не менее, в большинстве случаев это никогда не бывает Double.Epsilon.

18 голосов
/ 04 ноября 2012

Ваш something является double, и вы правильно определили это в строке

if (something == 0)

у нас есть double с левой стороны (lhs) и int с правой стороны (rhs).

Но теперь кажется, что вы думаете, что lhs будет преобразовано в int, и тогда знак == будет сравнивать два целых числа. Это не , что происходит. Преобразование из double в int является явным и не может происходить «автоматически».

Вместо этого происходит обратное. Значение rhs преобразуется в double, а затем знак == становится проверкой на равенство между двумя двойными числами. Это преобразование неявное (автоматическое).

Лучше (по мнению некоторых) писать

if (something == 0.0)

или

if (something == 0d)

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

В некоторых случаях также уместно ввести «толерантность», как в ответе Джона Скита, но эта терпимость тоже будет double. может, конечно, быть 1.0, если вы хотите, но это не должно быть [наименее строго положительным] целым числом.

15 голосов
/ 30 марта 2017

Если вы просто хотите отключить предупреждение, сделайте следующее:

if (something.Equals(0.0))

Конечно, это верное решение, только если вы знаете, что дрейф не является проблемой. Я часто делаю это, чтобы проверить, не собираюсь ли я делить на ноль.

4 голосов
/ 06 июля 2011

Я не думаю, что это равно, честно. Рассмотрим собственный пример: что-то = 0,9 или 0,0004. В первом случае это будет ЛОЖЬ, во втором - ИСТИНА. Имея дело с этими типами, я обычно определяю для меня процент точности и сравниваю в пределах этой точности. Зависит от ваших потребностей. что-то вроде ...

if(((int)(something*100)) == 0) {


//do something
}

Надеюсь, это поможет.

1 голос
/ 13 ноября 2018

Вот пример, представляющий проблему (подготовлен в LinQPad - если у вас его нет, просто используйте Console.Writeline вместо Dump метода):

void Main()
{
    double x = 0.000001 / 0.1;
    double y = 0.001 * 0.01; 

    double res = (x-y);
    res.Dump();
    (res == 0).Dump();
}

Теоретически x и y теоретическито же самое и равно: 0,00001, но из-за отсутствия «бесконечной точности» эти значения немного отличаются.К сожалению, достаточно немного, чтобы вернуть false при сравнении с 0 обычным способом.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...