Тестирование равенства с плавающей точкой - PullRequest
36 голосов
/ 27 октября 2010

Есть ли функция для проверки приближенного равенства с плавающей точкой в ​​python? Что-то вроде

 def approx_equal(a, b, tol):
     return abs(a - b) < tol

Мой пример использования подобен тому, как библиотека тестирования Google C ++, 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))

Ответы [ 6 ]

51 голосов
/ 05 ноября 2010
  • Для сравнения чисел существует math.isclose согласно PEP 485 начиная с Python 3.5.
  • Для сравнения чисел или массивов есть numpy.allclose.
  • Для проверки чисел или массивов есть numpy.testing.assert_allclose
19 голосов
/ 27 октября 2010

Другой подход заключается в вычислении относительного изменения (или относительной разности) двух чисел, которое «используется для сравнения двух величин с учетом« размеров »сравниваемых вещей». Две формулы , упомянутые в статье в Википедии, могут использоваться для сравнения, подобного следующему в 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 становится процентным значением). Обратите внимание, что в статье предполагается, что если изменяющееся значение «представляет собой сам процент, то лучше говорить о его изменении с использованием процентных пунктов» & mdash; т.е. абсолютное изменение.

Оба этих метода (очевидно) требуют немного больше вычислений, чем просто принятие абсолютного значения разности двух чисел, что может быть соображением.

8 голосов
/ 27 октября 2010

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

Что может быть более уместным.

Я не вижу, как вы можете запросить для функции (single) объединить все математические альтернативы. Так как это зависит от приложения.

5 голосов
/ 27 октября 2010

На вашем месте я бы просто использовал то, что вы написали, и либо поместил бы его в отдельный модуль (возможно, с другими утилитами, для которых у Python нет реализации), либо в верхней части кода, который требуется это.

Вы также можете использовать лямбда-выражение (одна из моих любимых языковых функций, но, вероятно, не совсем понятно):

approx_equal = lambda a, b, t: abs(a - b) < t
4 голосов
/ 27 октября 2010

Сравнение поплавков на равенство - это обычно плохая идея. Даже если вы используете функцию допуска, это не совсем то, что вы хотите сделать.

Если вы хотите использовать числа с плавающей запятой, разумным вариантом будет рефакторинг вашего алгоритма для использования неравенств, a < b, потому что это с большей вероятностью будет делать то, что вы ожидаете, с гораздо меньшим количеством ложных негативов или позитивов, и, что наиболее важно, это означает вам не нужно угадывать, насколько они равны, чтобы они были равны.

Если вы не можете сделать это, другой вариант - использовать точное представление. Если ваш алгоритм состоит только из арифметических операций (+, -, * и /), тогда вы можете использовать рациональное представление, как указано в fractions.Fraction, или, возможно, decimal.Decimal - это то, что вам нужно (например, с финансовыми расчетами).

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

0 голосов
/ 01 июля 2017

Согласно учебнику :

... Хотя числа нельзя приблизить к предполагаемым точным значениям, функция round () может быть полезна дляокругление так, чтобы результаты с неточными значениями становились сопоставимыми друг с другом ...

Таким образом, таким образом я определяю "isclose" функции в Python:обычно используют 5 как ndigits;Однако это зависит от точности, которую вы ожидаете.

...