Можно ли сравнить значения с плавающей точкой точно для обнуления?

Я знаю, что мы не можем сравнить 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)
24
задан Fakrudeen 5 March 2010 в 13:12
поделиться

7 ответов

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

Итак, вы должны проверить на 0 против вашей толерантности эпсилон.

17
ответ дан 28 November 2019 в 23:08
поделиться

Используйте допуск / 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
13
ответ дан 28 November 2019 в 23:08
поделиться

Поскольку ноль имеет точное представление, возможно, что значение сравнивается == с нулем. Если переменная, которую вы тестируете, была задана присваиванием или из введенного значения (как getVal в вашем примере?), она легко может быть нулевой. Но если она была результатом вычисления, то вероятность того, что она будет равна нулю, очень мала. Это усугубляется тем, что обычные десятичные дроби, такие как 0,2, не имеют точного представления в формате с плавающей запятой. Поэтому лучше всего использовать эпсилон.

3
ответ дан 28 November 2019 в 23:08
поделиться

Вы можете сравнить с нулем, если присвоили этой переменной ноль. Если вы получите ноль, например. вычитанием вы все равно можете получить очень маленькое число, близкое к нулю. например: 0,1-0,1 может быть оценено примерно как 1e-9.

13
ответ дан 28 November 2019 в 23:08
поделиться

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

0
ответ дан 28 November 2019 в 23:08
поделиться

Я бы по-прежнему рекомендовал следовать идиоме толерантности и не сравнивать точно с нулем.

2
ответ дан 28 November 2019 в 23:08
поделиться

Для сравнения с 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)
4
ответ дан 28 November 2019 в 23:08
поделиться