Найти тему
Машинное обучение

Числа с плавающей точкой

Многих новичков (и не очень новичков) может фрустрировать тот факт, что:

>>> 0.1 + 0.1 + 0.1 - 0.3

5.551115123125783e-17

😱 Нет, ваш Python не сломан, так и должно быть. Много слов уже сказано про представление чисел с точкой в компьютерах. Большинство наших вычислений производится согласно стандарту IEEE754 (👉читайте подбронее https://habr.com/post/112953/).

Если коротко, то числа в компьютере квантированы, то есть если упрощенно, они не непрерывны. Факт: числа 0.3 для компьютера не существует, зато есть самое ближайшее к нему число (3 - 5.551115123125783e-17).

Поэтому советуют никогда не сравнивать float-ы на точное равенство, когда один или оба операнда получены из вычислений:

>>> 0.3 == 0.3

True

>>> (0.1 + 0.1 + 0.1) == 0.3

False

Лучше сравнивать их приблизительно (модуль разницы с неким малым числом):

>>> def floats_equal(x, y, eps=1e-10): return abs(x - y) < eps

>>> floats_equal( 0.1 + 0.1 + 0.1, 0.3 )

True

💸 Если ваше приложение связано с подсчетом денег, точность всегда критична, иначе ваш баланс не сойдется. Для этого давно придуман модуль decimal (https://docs.python.org/3.6/library/decimal.html). В нем есть класс Decimal – фактически он представляет собой число с фиксированной точкой.

>>> from decimal import *

>>> Decimal(0.1)+Decimal(0.1)+Decimal(0.1)-Decimal(0.3)

Decimal('1.11022302E-17')

😤 Что за дела? Опять тоже самое! Дело в том, что нельзя получить "качественный" Decimal из обычного числа (мы помним, что 0.3 – не существует и будет подобрано ближайшее).

💡 Фишка в том, что нужно сначала преобразовать число в строку (str), а потом передать в Decimal. Тогда он будет явно знать какое число из реального мира мы хотим сохранить:

>>> Decimal(str(0.1)) + Decimal(str(0.1)) + Decimal(str(0.1)) - Decimal(str(0.3))

Decimal('0.0')

#python

Python/ django