Я знаю, что мы не можем сравнить 2 использования значений с плавающей точкой ==. Мы можем только выдержать сравнение, они в некотором интервале друг друга. Я знаю
if(val == 0.512)
происходит неправильно из-за ошибок, свойственных от вычислений с плавающей точкой и преобразования в двоичный файл, и должен быть
if (val in (0.512-epsilon, 0.512+epsilon))
Но действительно ли 0 является особенным? Мы можем сравнить плавания точно с 0? Или даже который является неправильным? Особенно в контексте C# и Java?
double val = 0;
val = getVal();
if(val == 0)
Несмотря на то, что 0 имеет точное представление, вы не можете полагаться на то, что результат вычисления с использованием чисел с плавающей запятой будет ровно 0. Как вы отметили, это из-за проблем с вычислением и преобразованием чисел с плавающей запятой.
Итак, вы должны проверить на 0 против вашей толерантности эпсилон.
Используйте допуск / ephsilon.
Я только что оценил следующее в Java, что математически дает ноль:
1.0/5.0 + 1.0/5.0 - 1.0/10.0 - 1.0/10.0 - 1.0/10.0 - 1.0/10.0
и фактически получил
2.7755575615628914E-17
Поскольку ноль имеет точное представление, возможно, что значение сравнивается == с нулем. Если переменная, которую вы тестируете, была задана присваиванием или из введенного значения (как getVal в вашем примере?), она легко может быть нулевой. Но если она была результатом вычисления, то вероятность того, что она будет равна нулю, очень мала. Это усугубляется тем, что обычные десятичные дроби, такие как 0,2, не имеют точного представления в формате с плавающей запятой. Поэтому лучше всего использовать эпсилон.
Вы можете сравнить с нулем, если присвоили этой переменной ноль. Если вы получите ноль, например. вычитанием вы все равно можете получить очень маленькое число, близкое к нулю. например: 0,1-0,1 может быть оценено примерно как 1e-9.
Я не думаю, что вы можете сделать это в общем случае - вычисления, которые происходят в getVal(), могут логически привести к нулю, но это не значит, что они вернут ноль. Если вы явно возвращаете ноль, чтобы указать на какое-то условие, то сравнение всегда должно работать, но я не думаю, что это лучшая практика. Я бы изменил функцию так, чтобы она возвращала код состояния и передавала изменяемое значение по ссылке.
Я бы по-прежнему рекомендовал следовать идиоме толерантности и не сравнивать точно с нулем.
Для сравнения с err все, что вам нужно, это.
// compare a and b with an ERR error.
if (Math.abs(a - b) <= ERR)
Для сравнения с 0
// compare a and 0 with an ERR error.
if (Math.abs(a) <= ERR)