Правильный способ сравнить System.Double с '0' (число, int?)

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

У меня есть это выражение 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.

Ответ 1

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

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

if (Math.Abs(something) < 0.001)

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

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

Ответ 2

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

if (something == 0)

имеем a double в левой части (lhs) и a int в правой части (rhs).

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

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

Считается лучше (кем-то) писать

if (something == 0.0)

или

if (something == 0d)

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

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

Ответ 3

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

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

Ответ 4

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

if (something.Equals(0.0))

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

Ответ 5

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

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


//do something
}

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