Тестирование равенства с плавающей точкой
Есть ли функция для проверки приближенного равенства с плавающей запятой в python? Что-то вроде,
def approx_equal(a, b, tol):
return abs(a - b) < tol
Мой пример использования похож на то, как библиотека тестирования Google С++, gtest.h, определяет EXPECT_NEAR
.
Вот пример:
def bernoulli_fraction_to_angle(fraction):
return math.asin(sqrt(fraction))
def bernoulli_angle_to_fraction(angle):
return math.sin(angle) ** 2
def test_bernoulli_conversions():
assert(approx_equal(bernoulli_angle_to_fraction(pi / 4), 0.5, 1e-4))
assert(approx_equal(
bernoulli_fraction_to_angle(bernoulli_angle_to_fraction(0.1)),
0.1, 1e-4))
Ответы
Ответ 1
- Для тестирования номеров есть
nose.tools.assert_almost_equal
и эквивалентно unittest.assertAlmostEqual
- Для тестирования чисел или массивов существует
numpy.testing.assert_allclose
- Для сравнения чисел существует
math.isclose
в соответствии с PEP 485 с Python 3.5.
- Для сравнения чисел или массивов существует
numpy.allclose
.
Ответ 2
Другим подходом является вычисление относительного изменения (или относительная разница) двух чисел, которое" используется для сравнения двух величин при принятии учитывать "размеры" сравниваемых вещей ". Две формулы , упомянутые в статье в Википедии, могут использоваться в сравнении, например, в Python, которые также обрабатывают случаи, когда одно или оба значения являются сравниваются ноль:
def approx_equal(a, b, tol):
return abs(a-b) <= max(abs(a), abs(b)) * tol
def approx_equal(a, b, tol):
return abs(a-b) <= (abs(a)+abs(b))/2 * tol
Вычисленное значение в любом случае является безразмерной фракцией. В первом случае базовое значение является максимальным абсолютным значением двух чисел, а во втором - его средним абсолютным значением. В статье обсуждаются все более подробно, а также их плюсы и минусы. Последний может превратиться в процентную разницу , если умножить на 100 до сравнения (с tol
став процентным значением). Обратите внимание, что в статье предполагается, что если изменяющееся значение "является самим процентом, лучше говорить о его изменении, используя процентные пункты" — т.е. абсолютное изменение.
Оба этих метода (очевидно) требуют немного большего вычисления, чем просто принятие абсолютного значения разности двух чисел, что может быть рассмотрено.
Ответ 3
Есть ли функция для проверки приближенного равенства с плавающей запятой в python?
Не может быть a, поскольку определение зависит от контекста.
def eq( a, b, eps=0.0001 ):
return abs(a - b) <= eps
Не всегда работает. Существуют обстоятельства, при которых
def eq( a, b, eps=0.0001 ):
return abs( a - b ) / abs(a) <= eps
может быть более уместным.
Плюс, там всегда популярны.
def eq( a, b, eps=0.0001 ):
return abs(math.log( a ) - math.log(b)) <= eps
Что может быть более подходящим.
Я не вижу, как вы можете запросить a (одиночную) функцию объединить все математические альтернативы. Поскольку это зависит от приложения.
Ответ 4
Если бы я был вами, я бы просто использовал то, что вы написали, и либо поместил его в отдельный модуль (возможно, с другими утилит, которые вам нужны, для чего у Python нет реализации) или наверху любого кода требуется он.
Вы также можете использовать выражение лямбда (одна из моих любимых функций языка, но, вероятно, менее ясная):
approx_equal = lambda a, b, t: abs(a - b) < t
Ответ 5
Сравнение поплавков для равенства - это обычно плохая идея. Даже с использованием функции допуска, которую вы используете, это не то, что вы хотите сделать.
Если вы хотите использовать поплавки, разумным вариантом является рефакторинг вашего алгоритма для использования неравенств a < b
, потому что это, скорее всего, будет делать то, что вы ожидаете, с гораздо меньшим количеством ложных негативов или положительных результатов, и что самое главное, это означает вам не нужно угадывать, насколько они равны, чтобы они были равны.
Если вы не можете этого сделать, другой вариант - использовать точное представление. Если ваш алгоритм состоит только из арифметических операций (+
, -
, *
и /
), тогда вы можете использовать рациональное представление, предоставленное fractions.Fraction
, или, возможно, decimal.Decimal
- это то, что вы хотите (например, с финансовыми расчетами).
Если ваш алгоритм не может быть легко выражен с помощью произвольного представления точности, другой выбор заключается в том, чтобы явно управлять ошибкой округления с интервальной арифметикой, например, с этот модуль.
Ответ 6
Согласно учебник:
... Хотя числа не могут быть приближены к их предполагаемым точным значениям, функция round() может быть полезна для округления, так что результаты с неточными значениями становятся сравнимыми друг с другом...
Следовательно, так я определяю функции "isclose" в Python:
def isclose(a, b, ndigits):
return round(a-b, ndigits) == 0
Обычно я использую 5 как ndigits
; Однако это зависит от точности, которую вы ожидаете.