для бинарной математики, числа, не являющиеся равными степени двойки, зача-
стую не могут быть выражены точно:
>>> x = 10.0 / 3.0
>>> x
3.3333333333333335
Эй, что это за пятерка в конце? На ее месте должна быть тройка. С помощью
модуля decimal (http://docs.python.org/3/library/decimal.html) вы можете записывать
числа с желаемым уровнем точности. Это особенно важно для расчетов денежных
сумм. Сумма в валюте Соединенных Штатов не может быть меньше 1 цента (сотая
часть доллара), поэтому, если мы подсчитываем количество долларов и центов, нам
нужно считать все до копеечки. Если мы попробуем представить доллары и центы
как значения с плавающей точкой вроде 19,99 или 0,06, то потеряем некоторую
часть точности в последних битах еще до начала вычислений. Как с этим справить-
ся? Легко. Нам нужно использовать модуль decimal:
>>> from decimal import Decimal
>>> price = Decimal('19.99')
>>> tax = Decimal('0.06')
>>> total = price + (price * tax)
>>> total
Decimal('21.1894')
Мы записали цену и налог как строковые значения, чтобы сохранить их точ-
ность. При вычислении переменной total мы обработали все значащие части
цента, но хотим получить ближайшее целое значение цента:
>>> penny = Decimal('0.01')
>>> total.quantize(penny)
Decimal('21.19')
412
Приложение В. Py в науке
Такие же результаты можно получить с помощью старых добрых чисел с пла-
вающей точкой и округлений, но не всегда. Вы можете умножить сумму на 100
и использовать при подсчетах количество центов, но и при таком подходе можете
пострадать. Этот вопрос обсуждается на сайте www.itmaybeahack.com.
Выполняем вычисления для рациональных чисел
с помощью модуля fractions
Вы можете представлять числа как числитель, разделенный на знаменатель, с по-
мощью модуля стандартной библиотеки fractions (http://docs.python.org/3/library/
fractions.html). Рассмотрим пример простой операции умножения 1/3 на 2/3:
>>> from fractions import Fraction
>>> Fraction(1, 3) * Fraction(2, 3)
Fraction(2, 9)
Аргументы с плавающей точкой могут быть неточными, поэтому вы можете
использовать модуль Decimal вместе с модулем Fraction:
>>> Fraction(1.0/3.0)
Fraction(6004799503160661, 18014398509481984)
>>> Fraction(Decimal('1.0')/Decimal('3.0'))
Fraction(3333333333333333333333333333, 10000000000000000000000000000)
Получим наибольший общий делитель для двух чисел с помощью функции gcd:
>>> import fractions
>>> fractions.gcd(24, 16)