Модуль decimal

Последнее обновление: 04.02.2022

При работе с числами с плавающей точкой (то есть float) мы сталкиваемся с тем, что в результате вычислений мы получаем не совсем верный результат:

number = 0.1 + 0.1 + 0.1
print(number)       # 0.30000000000000004

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

Ключевым компонентом для работы с числами в этом модуле является класс Decimal. Для его применения нам надо создать его объект с помощью конструктора. В конструктор передается строковое значение, которое представляет число:

from decimal import Decimal

number = Decimal("0.1")

После этого объект Decimal можно использовать в арифметических операциях:

from decimal import Decimal

number = Decimal("0.1")
number = number + number + number
print(number)       # 0.3

В операциях с Decimal можно использовать целые числа:

number = Decimal("0.1")
number = number + 2

Однако нельзя смешивать в операциях дробные числа float и Decimal:

number = Decimal("0.1")
number = number + 0.1	# здесь возникнет ошибка

С помощью дополнительных знаков мы можем определить, сколько будет символов в дробной части числа:

number = Decimal("0.10")
number = 3 * number
print(number)       # 0.30

Строка "0.10" определяет два знака в дробной части, даже если последние символы будут представлять ноль. Соответственно "0.100" представляет три знака в дробной части.

Округление чисел

Объекты Decimal имеют метод quantize(), который позволяет округлять числа. В этот метод в качестве первого аргумента передается также объект Decimal, который указывает формат округления числа:

from decimal import Decimal

number = Decimal("0.444")
number = number.quantize(Decimal("1.00"))
print(number)       # 0.44

number = Decimal("0.555678")
print(number.quantize(Decimal("1.00")))       # 0.56

number = Decimal("0.999")
print(number.quantize(Decimal("1.00")))       # 1.00

Используемая строка "1.00" указывает, что округление будет идти до двух знаков в дробной части.

По умолчанию округление описывается константой ROUND_HALF_EVEN, при котором округление происходит до ближайшего четного числа, если округляемая часть равна 5. Например:

from decimal import Decimal, ROUND_HALF_EVEN


number = Decimal("10.025")      # 2 - ближайшее четное число
print(number.quantize(Decimal("1.00"), ROUND_HALF_EVEN))       # 10.02

number = Decimal("10.035")      # 4 - ближайшее четное число
print(number.quantize(Decimal("1.00"), ROUND_HALF_EVEN))       # 10.04

Стратегия округления передается в качестве второго параметра в quantize.

Строка "1.00" означает, что округление будет идти до двух чисел в дробной части. Но в первом случае "10.025" - вторым знаком идет 2 - четное число, поэтому, несмотря на то, что следующее число 5, двойка не округляется до тройки.

Во втором случае "10.035" - вторым знаком идет 3 - нечетное число, ближайшим четным числом будет 4, поэтому 35 округляется до 40.

Данное поведение при округлении, возможно, не всем покажется желательным, и в этом случае его можно переопределить, использовав одну из следующих констант:

  • ROUND_HALF_UP: округляет число в сторону повышения, если после него идет число 5 или выше

  • ROUND_HALF_DOWN: округляет число в сторону повышения, если после него идет число больше 5

    number = Decimal("10.026")
    print(number.quantize(Decimal("1.00"), ROUND_HALF_DOWN))       # 10.03
    
    number = Decimal("10.025")
    print(number.quantize(Decimal("1.00"), ROUND_HALF_DOWN))       # 10.02
    
  • ROUND_05UP: округляет 0 до единицы, если после него идет число 5 и выше

    number = Decimal("10.005")
    print(number.quantize(Decimal("1.00"), ROUND_05UP))       # 10.01
    
    number = Decimal("10.025")
    print(number.quantize(Decimal("1.00"), ROUND_05UP))       # 10.02
    
  • ROUND_CEILING: округляет число в большую сторону вне зависимости от того, какое число идет после него

    number = Decimal("10.021")
    print(number.quantize(Decimal("1.00"), ROUND_CEILING))       # 10.03
    
    number = Decimal("10.025")
    print(number.quantize(Decimal("1.00"), ROUND_CEILING))       # 10.03
    
  • ROUND_FLOOR: не округляет число вне зависимости от того, какое число идет после него

    number = Decimal("10.021")
    print(number.quantize(Decimal("1.00"), ROUND_FLOOR))       # 10.02
    
    number = Decimal("10.025")
    print(number.quantize(Decimal("1.00"), ROUND_FLOOR))       # 10.02
    
Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850