Два очень маленьких числа кажутся одинаковыми для задачи, но math.isclose возвращает False. Обычно дело не в том, что Python «сломался», а в том, какой допуск указан в вызове. На трех учебных парах разберем разницу между относительным и абсолютным допуском и проверим, почему сравнение с нулем требует отдельного решения.
Все пары и допуски ниже придуманы для демонстрации поведения функции. Это не нормы точности измерительного прибора и не допустимая ошибка реального исследования. Код выполнен в Python 3.12.14, документация взята из ветви 3.12. Результат True означает, что выполнено выбранное вычислительное условие. Он не доказывает равенство величин и не говорит о качестве данных.
Как функция решает, достаточно ли близки числа
В документации math.isclose приведено условие для обычных конечных чисел: abs(a-b) <= max(rel_tol * max(abs(a), abs(b)), abs_tol). Относительная часть масштабируется по большему модулю двух чисел. Абсолютная часть задает порог разности в тех же единицах, что a и b. Используется максимум двух частей, а не их сумма.
По умолчанию rel_tol=1e-9 и abs_tol=0.0. Если сравнивать ненулевое x с нулем, одна относительная часть при rel_tol меньше 1 положительного результата не даст: разность abs(x) больше rel_tol * abs(x). Поэтому положительный абсолютный допуск около нуля нужно обосновать задачей, а не добавлять только ради True.
| Учебная пара | По умолчанию / выбранный режим |
|---|---|
| 0 и 1e-10 | False / True |
| 1000 и 1000.001 | False / True |
| 1 и 1.1 | False / False |

Для всех трех строк выбран один режим: rel_tol=1e-6, abs_tol=1e-9. Не читайте таблицу так, будто абсолютный допуск объясняет каждую строку отдельно: во второй паре решает относительная часть. Первая строка, наоборот, показывает проблему сравнения с нулем.
Полный код: три пары и особые значения
default означает результат с параметрами по умолчанию, selected — результат с явно заданными допусками. В конце отдельно показаны NaN и положительная бесконечность, чтобы True и False не принимали за проверку пригодности произвольных данных к анализу.
from math import isclose
pairs = [(0.0, 1e-10), (1000.0, 1000.001), (1.0, 1.1)]
results = []
for a, b in pairs:
default = isclose(a, b)
selected = isclose(a, b, rel_tol=1e-6, abs_tol=1e-9)
results.append((default, selected))
print(f"{a!r} vs {b!r}: default={default}; selected={selected}")
print("nan_close =", isclose(float("nan"), float("nan")))
print("inf_close =", isclose(float("inf"), float("inf")))
assert results == [(False, True), (False, True), (False, False)]
assert not isclose(float("nan"), float("nan"))
assert isclose(float("inf"), float("inf"))
0.0 vs 1e-10: default=False; selected=True
1000.0 vs 1000.001: default=False; selected=True
1.0 vs 1.1: default=False; selected=False
nan_close = False
inf_close = True
В первой паре разность 1e-10 меньше выбранного abs_tol=1e-9, поэтому получается True. Во второй разность около 0.001 сравнивается с относительным порогом около 0.001000001 и укладывается в него. Для 1 и 1.1 разность около 0.1 заметно больше порога около 0.0000011, поэтому остается False. Десятичные записи здесь нужны, чтобы показать масштаб: код работает с float, а не с точной десятичной арифметикой.
Документация отдельно оговаривает особые значения: NaN не считается близким даже самому себе, бесконечность близка только самой себе с тем же знаком. Показанное inf_close=True не делает бесконечность пригодным наблюдением. Состав и допустимость входных данных проверяют отдельно, этот фрагмент не заменяет валидатор.
Как выбрать и описать допуски
| Параметр или решение | Что записать в методике |
|---|---|
| rel_tol | Безразмерный относительный допуск и обоснование масштаба сравнения. |
| abs_tol | Абсолютный допуск с единицами сравниваемых величин; особенно важен около нуля. |
| Состав пар | Какие значения сравнивают и что делают с пропусками и особыми значениями. |
| Смысл результата | Выполнено ли условие допуска; это не статистический тест и не доверительный интервал. |
Сначала разберитесь с единицами. Один и тот же числовой абсолютный допуск для метров и миллиметров означает разную физическую величину. Относительный допуск проблему нуля не снимает. Не поднимайте пороги подряд, пока нужные пары не дадут True, а потом не выдавайте этот выбор за заранее заданное правило.
Сравнение близости также не исправляет исходное число и не округляет его для таблицы. О представлении значений в float рассказывает официальное руководство Python. Если задача состоит именно в сохранении исходной десятичной записи, используйте отдельный разбор Decimal после float: у сравнения по допуску и округления разные цели.
- До просмотра результатов определите смысл сравнения, единицы и допустимые отклонения.
- Сохраните оба параметра явно, даже если один из них совпадает с умолчанием.
- Проверьте нуль, положительные и отрицательные конечные значения в своем диапазоне: три пары не покрывают все входы.
- Отдельно опишите пропуски и особые значения. Не заменяйте проверку данных одним вызовом isclose.
Если нужно согласовать вычислительное сравнение с исследовательской задачей, на странице помощи со статистическим анализом можно обсудить состав консультации. Передайте исходные пары, единицы и причину выбора порогов. Само увеличение числа совпадений не является улучшением качества измерений и не подтверждает содержательную гипотезу.