Это довольно распространенная проблема с числами с плавающей запятой. Я решаю это на основе обсуждения в Разделе 1.5 Деммеля [1]. (1) Рассчитать ошибку округления. (2) Убедитесь, что ошибка округления меньше некоторого эпсилона. Некоторое время я не использовал python и имел только версию 2.4.3, но постараюсь исправить это.
Шаг 1. Ошибка округления
def roundoff_error(exact, approximate):
return abs(approximate/exact - 1.0)
Шаг 2. Равенство с плавающей точкой
def float_equal(float1, float2, epsilon=2.0e-9):
return (roundoff_error(float1, float2) < epsilon)
У этого кода есть несколько явных недостатков.
- Ошибка деления на ноль, если точное значение равно нулю.
- Не проверяет, что аргументы являются значениями с плавающей запятой.
Редакция 1.
def roundoff_error(exact, approximate):
if (exact == 0.0 or approximate == 0.0):
return abs(exact + approximate)
else:
return abs(approximate/exact - 1.0)
def float_equal(float1, float2, epsilon=2.0e-9):
if not isinstance(float1,float):
raise TypeError,"First argument is not a float."
elif not isinstance(float2,float):
raise TypeError,"Second argument is not a float."
else:
return (roundoff_error(float1, float2) < epsilon)
Это немного лучше. Если точное или приблизительное значение равно нулю, ошибка равна значению другого. Если что-то кроме значения с плавающей запятой предоставлено, возбуждается TypeError.
На данный момент единственной трудной вещью является установка правильного значения для эпсилона. В документации для версии 2.6.1 я заметил, что в sys.float_info есть атрибут epsilon, поэтому я бы использовал это значение в два раза больше, чем значение по умолчанию epsilon. Но правильное значение зависит как от вашего приложения, так и от вашего алгоритма.
[1] Джеймс В. Деммель, Прикладная числовая линейная алгебра , SIAM, 1997.