Подходит ли использование машины epsilon для тестов на равенство с плавающей точкой? - PullRequest
10 голосов
/ 19 июля 2010

Это продолжение Проверка на равенство значений с плавающей точкой: существует ли стандартное имя для константы «точности»? .Существует очень похожий вопрос Double.Epsilon о равенстве, больше, меньше, меньше или равно, больше или равно .


Хорошо известно, что тест на равенство для двух значений с плавающей точкой x и y должен выглядеть примерно так (а не просто =):

abs ( x - y ) <<em> epsilon , где epsilon - очень небольшое значение.

Как выбрать значение для epsilon ?

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

Например, .NET Framework предлагает константу System.Double.Epsilon (= 4.94066 × 10 -324 ),который представляет наименьшее положительное значение System.Double, которое больше нуля.

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

0 + System.Double.Epsilon ≠ 0

1 + System.Double.Epsilon = 1 (!)

, что, если я правильно понимаю, потому что эта константа меньше чем машинный эпсилон .

→ Это правильно?

→ Означает ли этотакже означает, что я могу надежно использовать epsilon: = machine epsilon для тестов на равенство?

Удалены эти два вопроса, поскольку на них уже адекватно ответил второй вопрос SO, связанный с выше.


В статье, связанной с Википедией, говорится, что для 64-битных чисел с плавающей точкой (т. Е. Типа double во многих языках) машинный эпсилон равен:

2 -53 или ок.0,000000000000000111 (число с 15 нулями после десятичной точки)

→ Из этого следует, что все 64-битные значения с плавающей запятой гарантированно будут точными до 14 (если не 15)цифры?

Ответы [ 4 ]

11 голосов
/ 19 июля 2010

Как выбрать значение для эпсилона?

Краткий ответ: Вы берете небольшое значение, которое соответствует потребностям ваших приложений.

Длинный ответ: Никто не может знать, какие вычисления выполняет ваше приложение и насколько точный вы ожидаете, что ваши результаты будут. Так как ошибки округления суммируются, эпсилон машины почти всегда будет слишком большим, поэтому вы должны выбрать свое значение. В зависимости от ваших потребностей будет достаточно 0,01 или, может быть, 0,00000000000001 или менее.

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

5 голосов
/ 19 июля 2010

Раньше, когда мне приходилось использовать значение эпсилона, оно было намного больше значения эпсилона машины.

Хотя это было для 32-битных двойных чисел (а не для 64-битных двойных), мы обнаружили, что значение epsilon 10 -6 было необходимо для большинства (если не всех) вычисляемых значений в нашем конкретном случае. применение .

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

Вам нужно поэкспериментировать, выполнить расчеты и проверить разницу между вашими выходными значениями. Только когда вы знаете диапазон ваших потенциальных ответов, вы сможете выбрать подходящее значение для вашего приложения .

4 голосов
/ 26 февраля 2015

Печальная правда в том, что: Не существует подходящего эпсилона для сравнений с плавающей точкой. Используйте другой подход для тестов на равенство с плавающей точкой, если вы не хотите сталкиваться с серьезными ошибками.

Приблизительное сравнение с плавающей точкой - удивительно сложное поле, и подход abs(x - y) < eps работает только для очень ограниченного диапазона значений, главным образом из-за абсолютной разницы, не учитывающей величину сравниваемых значений, но также и из-за к аннулированию значащей цифры, возникающему при вычитании двух значений с плавающей запятой с различными показателями степени.

Существуют лучшие подходы, использующие относительные различия или ULP, но у них есть свои недостатки и подводные камни. Прочитайте замечательную статью Брюса Доусона Сравнение чисел с плавающей запятой, выпуск 2012 г. , чтобы узнать, насколько сложными являются сравнения с плавающей запятой - это необходимо прочитать любому, кто занимается программированием с плавающей запятой ИМХО! Я уверен, что бесчисленные тысячи человеко-лет были потрачены на поиск тонких ошибок из-за наивных сравнений с плавающей точкой.

2 голосов
/ 23 января 2014

У меня также есть вопросы относительно правильной процедуры.Однако я считаю, что нужно сделать:

abs(x - y) <= 0.5 * eps * max(abs(x), abs(y))

вместо:

abs(x - y) < eps

Причина этого связана с определением эпсилона машины.Используя код Python:

import numpy as np
real = np.float64
eps = np.finfo(real).eps

## Let's get the machine epsilon
x, dx = real(1), real(1)
while x+dx != x: dx/= real(2) ;

print "eps = %e  dx = %e  eps*x/2 = %e" % (eps, dx, eps*x/real(2))

, который дает: eps = 2.220446e-16 dx = 1.110223e-16 eps*x/2 = 1.110223e-16

## Now for x=16
x, dx = real(16), real(1)
while x+dx != x: dx/= real(2) ;

print "eps = %e  dx = %e  eps*x/2 = %e" % (eps, dx, eps*x/real(2))

, который теперь дает: eps = 2.220446e-16 dx = 1.776357e-15 eps*x/2 = 1.776357e-15

## For x not equal to 2**n
x, dx = real(36), real(1)
while x+dx != x: dx/= real(2) ;

print "eps = %e  dx = %e  eps*x/2 = %e" % (eps, dx, eps*x/real(2))

, который возвращает: eps = 2.220446e-16 dx = 3.552714e-15 eps*x/2 = 3.996803e-15

Однако, несмотря на разницу между dx и eps * x / 2, мы видим, что dx <= eps*x/2, таким образом, он служит для проверки на равенство, проверки на допуски при проверке на сходимость в числовых процедурах и т. Д.

Это похоже на то, что есть в: www.ibiblio.org / pub / languages ​​/ fortran / ch1-8.html # 02 , однако, если кто-то знает о лучших процедурах или что-то здесьневерно, пожалуйста, скажите.

...