Подтвердить что ты не робот

Тестирование равенства с плавающей точкой

Есть ли функция для проверки приближенного равенства с плавающей запятой в 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))
4b9b3361

Ответ 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; Однако это зависит от точности, которую вы ожидаете.