Số dấu phẩy động được biểu diễn trong bộ nhớ dưới dạng phân số nhị phân cơ số 2. Kết quả là các phép toán số học dấu phẩy động có thể kỳ quặc đôi khi. Cộng 0.1 và 0.2 có thể cho kết quả phiền toái như sau:
>>> 0.1 + 0.2 0.30000000000000004
Trên thực tế đây là bản chất của biểu diễn dấu phẩy động nhị phân. Điều này phổ biến trong bất kỳ ngôn ngữ lập trình nào. Python cung cấp mô-đun decimal để thực hiện số học dấu phẩy động nhanh và làm tròn đúng.
Mô-đun decimal được thiết kế để biểu diễn dấu phẩy động chính xác như mong muốn, và kết quả phép toán số học nhất quán với kỳ vọng. Mức độ chính xác của biểu diễn và phép toán có thể thiết lập lên tới 28 chữ số.
Mô-đun decimal định nghĩa lớp Decimal. Đối tượng Decimal có thể được khai báo bằng cách đưa một số nguyên, một chuỗi có biểu diễn số hoặc một tuple làm tham số cho constructor của nó:
>>> from decimal import Decimal
>>> d1 = Decimal(10)
>>> d1
Decimal('10')
>>> d2 = Decimal('10')
>>> d2
Decimal('10')Tham số tuple chứa ba phần tử: dấu (0 cho dương, 1 cho âm), một tuple các chữ số và số mũ. Ví dụ:
>>> d3 = Decimal((1, (1, 2, 3, 4), 2))
>>> d3
Decimal('-1.234E+5')Một cách thuận tiện hơn để biểu diễn số dấu phẩy động độ chính xác cụ thể là lấy môi trường ngữ cảnh (context) của luồng hiện tại bằng hàm getcontext() và thiết lập độ chính xác cho đối tượng Decimal.
>>> from decimal import Decimal, getcontext
>>> getcontext().prec = 5
>>> d3 = Decimal(10)
>>> d4 = Decimal(3)
>>> d3 / d4
Decimal('3.3333')Ngữ cảnh (Contexts) là môi trường cho các phép toán số học dùng để xác định độ chính xác và định nghĩa quy tắc làm tròn cũng như giới hạn phạm vi cho số mũ.
decimal.getcontext() - Trả về ngữ cảnh hiện tại cho luồng hoạt động.
decimal.setcontext(c) - Thiết lập ngữ cảnh hiện tại cho luồng hoạt động thành c.
Các hằng số chế độ làm tròn sau được định nghĩa trong mô-đun decimal:
| ROUND_CEILING | Làm tròn về phía Vô cực. |
| ROUND_DOWN | Làm tròn về phía không. |
| ROUND_FLOOR | Làm tròn về phía -Vô cực. |
| ROUND_HALF_DOWN | Làm tròn đến gần nhất với ties về phía không. |
| ROUND_HALF_EVEN | Làm tròn đến gần nhất với ties đến số chẵn gần nhất. |
| ROUND_HALF_UP | Làm tròn đến gần nhất với ties ra xa từ không. |
| ROUND_UP | Làm tròn ra xa từ không. |
| ROUND_05UP | Làm tròn ra xa từ không nếu chữ số cuối sau làm tròn về phía không sẽ là 0 hoặc 5; ngược lại làm tròn về phía không. |
Đoạn mã sau sử dụng tham số độ chính xác và làm tròn của đối tượng ngữ cảnh:
>>> from decimal import *
>>> getcontext().prec = 5
>>> getcontext().rounding = ROUND_UP
>>> d1 = Decimal(100)
>>> d2 = Decimal(6)
>>> d1 / d2
Decimal('16.667')Các phép toán số học trên đối tượng Decimal:
Tất cả các phép toán số học thông thường được thực hiện trên đối tượng Decimal, rất giống như float bình thường.
>>> a = Decimal('2.4')
>>> b = Decimal('1.2')
>>> a + b
Decimal('3.6')
>>> a - b
Decimal('1.2')
>>> b - a
Decimal('-1.2')
>>> a * b
Decimal('2.88')
>>> a / b
Decimal('2')Phép toán số học có thể thực hiện trên một toán hạng Decimal và một toán hạng số nguyên. Tuy nhiên với đối tượng dấu phẩy động bình thường, phép toán là không hợp lệ.
>>> a = Decimal('2.4')
>>> c = 2.1
>>> a + c
Traceback (most recent call last):
File "<pyshell#37>", line 1, in <module>
a + c
TypeError: unsupported operand type(s) for +: 'decimal.Decimal' and 'float'Ngoại lệ tương tự xảy ra cho tất cả các phép toán số học.
Hành vi của toán tử dư (%) với đối tượng Decimal hơi khác với kiểu số thông thường. Ở đây, dấu của kết quả là của số bị chia (dividend) chứ không phải của số chia (divisor).
>>> -7 % 3
2
>>> 7 % -3
-2
>>> Decimal(-7) % Decimal(3)
Decimal('-1')
>>> Decimal(7) % Decimal(-3)
Decimal('1')Decimal.from_float() - Hàm này chuyển đổi float bình thường thành đối tượng Decimal với biểu diễn nhị phân chính xác. Kết quả là from_float(0.1) và Decimal('0.1') không giống nhau.
>>> d1 = Decimal('0.1')
>>> d2 = Decimal.from_float(0.1)
>>> d1, d2
(Decimal('0.1'), Decimal('0.1000000000000000055511151231257827021181583404541015625'))Bài viết này giải thích việc sử dụng chức năng được định nghĩa trong mô-đun decimal của thư viện chuẩn Python.