Hướng dẫn decimal function in python - hàm thập phân trong python

Vietnamese (Tiếng Việt) translation by Dai Phong (you can also view the original English article) Dai Phong (you can also view the original English article)

Ngay cả những phép toán cơ bản nhất có thể đôi khi cho ra một kết quả sai. Điều này xảy ra do các hạn chế trong việc lưu trữ giá trị chính xác của một số. Bạn có thể vượt qua những hạn chế này bằng cách sử dụng mô-đun decimal trong Python. Tương tự, mô-đun math lẫn cmath mà chúng ta đã học được trong hướng dẫn trước của chúng tôi đều không thể giúp chúng ta thực hiện phép tính số học dựa theo phân số. Tuy nhiên, mô-đun fractions trong Python thực hiện chính xác điều đó.

Trong hướng dẫn này, bạn sẽ tìm hiểu về cả hai mô-đun này và các hàm khác nhau mà chúng cung cấp.

Tại sao Chúng ta Cần Mô-đun Decimal?

Có lẽ bạn sẽ tự hỏi tại sao chúng ta cần một mô-đun để thực hiện phép toán số học cơ bản với các số thập phân khi chúng ta có thể làm như vậy bằng cách sử dụng float.

Trước khi tôi trả lời câu hỏi này, tôi muốn bạn đoán về giá trị đầu ra nếu bạn gõ 0.1 + 0.2 trong giao diện console của Python. Nếu bạn đoán rằng đầu ra là 0.3, thì bạn sẽ ngạc nhiên khi bạn kiểm tra kết quả thực tế, đó là 0.30000000000000004. Bạn có thể thử một số phép tính khác như 0.05 + 0.1 và bạn sẽ nhận được 0.15000000000000002.

Để hiểu điều gì đang xảy ra ở đây, hãy cố gắng biểu diễn

from decimal import Decimal

Decimal('0.05') + Decimal('0.1')
# returns Decimal('0.15')

Decimal(0.05) + Decimal(0.1)
# returns Decimal('0.1500000000000000083266726847')
0 ở dạng thập phân, và bạn sẽ nhận thấy rằng số này thật sự không dừng lại ở cơ số 10. Tương tự như vậy, một số số như 0.1 hoặc 1/10 không dừng lại ở cơ số 2. Vì những con số này vẫn cần phải được biểu diễn bằng cách nào đó, một số xấp xỉ được tạo ra khi lưu trữ chúng, dẫn đến những sai số đó.

Số 0.30000000000000004 thực sự rất gần với 0,3, do đó, phần lớn chúng ta có thể bỏ đi phần xấp xỉ này. Thật không may, phần xấp xỉ này sẽ không thể loại bỏ khi bạn đang mô phỏng một vụ phóng vệ tinh hoặc xử lý tiền. Một vấn đề khác với những xấp xỉ này là các lỗi vẫn tiếp tục tồn tại.

Để có được những kết quả chính xác mà chúng ta thường xử lý với chúng khi thực hiện các phép tính bằng tay, chúng ta cần một cái gì đó hỗ trợ tính toán số thập phân dấu chấm động một cách nhanh chóng, chính xác và mô-đun decimal thực hiện chính xác điều đó.

Sử dụng Mô-đun Decimal

Trước khi sử dụng mô-đun, bạn cần phải import nó trước. Sau đó, bạn có thể tạo các số thập phân từ các số nguyên, chuỗi, float, hoặc tuple. Khi số thập phân đã được cấu trúc từ một số nguyên hoặc một float, có một sự chuyển đổi chính xác của giá trị số đó. Hãy xem các ví dụ dưới đây để biết rõ tôi muốn nói gì:

from decimal import Decimal

Decimal(121)
# returns Decimal('121')

Decimal(0.05)
# returns Decimal('0.05000000000000000277555756')

Decimal('0.05')
# returns Decimal('0.05')

Decimal((0, (8, 3, 2, 4), -3))
# returns Decimal('8.324')

Decimal((1, (8, 3, 2, 4), -1))
# returns Decimal('-832.4')

Như bạn thấy, giá trị của

from decimal import Decimal

Decimal('0.05') + Decimal('0.1')
# returns Decimal('0.15')

Decimal(0.05) + Decimal(0.1)
# returns Decimal('0.1500000000000000083266726847')
1 hơi khác so với
from decimal import Decimal

Decimal('0.05') + Decimal('0.1')
# returns Decimal('0.15')

Decimal(0.05) + Decimal(0.1)
# returns Decimal('0.1500000000000000083266726847')
2. Điều này có nghĩa là khi bạn cộng 0.05 và 0.1, bạn nên sử dụng
from decimal import Decimal

Decimal('0.05') + Decimal('0.1')
# returns Decimal('0.15')

Decimal(0.05) + Decimal(0.1)
# returns Decimal('0.1500000000000000083266726847')
3 và
from decimal import Decimal

Decimal('0.05') + Decimal('0.1')
# returns Decimal('0.15')

Decimal(0.05) + Decimal(0.1)
# returns Decimal('0.1500000000000000083266726847')
4 để cấu trúc các số thập phân.

from decimal import Decimal

Decimal('0.05') + Decimal('0.1')
# returns Decimal('0.15')

Decimal(0.05) + Decimal(0.1)
# returns Decimal('0.1500000000000000083266726847')

Bây giờ bạn có thể thực hiện các phép toán khác nhau trên các số thập phân, bạn có thể muốn kiểm soát độ chính xác hoặc làm tròn cho những phép toán đó. Điều này có thể được thực hiện bằng cách sử dụng hàm

from decimal import Decimal

Decimal('0.05') + Decimal('0.1')
# returns Decimal('0.15')

Decimal(0.05) + Decimal(0.1)
# returns Decimal('0.1500000000000000083266726847')
5. Hàm này cho phép bạn lấy cũng như thiết lập giá trị của các tuỳ chọn chính xác và làm tròn, cùng với những thứ khác.

Xin lưu ý rằng cả làm tròn và độ chính xác chỉ có tác dụng trong các phép toán số học chứ không phải lúc bạn tự tạo ra bản thân các số thập phân.

import decimal
from decimal import Decimal, getcontext

Decimal(1) / Decimal(13)
# returns Decimal('0.07692307692307692307692307692')

getcontext().prec = 10

Decimal(0.03)
# returns Decimal('0.02999999999999999888977697537')

Decimal(1) / Decimal(7)
# returns Decimal('0.1428571429')

getcontext().rounding = decimal.ROUND_DOWN

Decimal(1) / Decimal(7)
# returns Decimal('0.1428571428')

Bạn cũng có thể sử dụng một số hàm toán học như

from decimal import Decimal

Decimal('0.05') + Decimal('0.1')
# returns Decimal('0.15')

Decimal(0.05) + Decimal(0.1)
# returns Decimal('0.1500000000000000083266726847')
6,
from decimal import Decimal

Decimal('0.05') + Decimal('0.1')
# returns Decimal('0.15')

Decimal(0.05) + Decimal(0.1)
# returns Decimal('0.1500000000000000083266726847')
7, và
from decimal import Decimal

Decimal('0.05') + Decimal('0.1')
# returns Decimal('0.15')

Decimal(0.05) + Decimal(0.1)
# returns Decimal('0.1500000000000000083266726847')
8 với các số thập phân. Dưới đây là vài ví dụ:

import decimal
from decimal import Decimal, getcontext

Decimal(2).sqrt()
# returns Decimal('1.414213562373095048801688724')

getcontext().prec = 4

Decimal('2').sqrt()
# returns Decimal('1.414')

Decimal('2000').log10()
# returns Decimal('3.301')

Sử dụng Mô-đun Fractions

Đôi khi, bạn có thể phải đối mặt với những tình huống nơi mà bạn cần phải thực hiện các phép toán khác nhau trên phân số hoặc kết quả cuối cùng cần phải là một phân số. Mô-đun fractions có thể rất hữu ích trong những trường hợp này. Nó cho phép bạn tạo ra một đối tượng

from decimal import Decimal

Decimal('0.05') + Decimal('0.1')
# returns Decimal('0.15')

Decimal(0.05) + Decimal(0.1)
# returns Decimal('0.1500000000000000083266726847')
9 từ các con số, số float, số thập phân, và thậm chí cả chuỗi. Cũng giống như mô-đun decimal, có một số vấn đề với mô-đun này cũng như khi nói đến việc tạo các phân số từ các số float. Dưới đây là vài ví dụ:

from fractions import Fraction
from decimal import Decimal

Fraction(11, 35)
# returns Fraction(11, 35)

Fraction(10, 18)
# returns Fraction(5, 9)

Fraction('8/25')
# returns Fraction(8, 25)

Fraction(1.13)
# returns Fraction(1272266894732165, 1125899906842624)

Fraction('1.13')
# returns Fraction(113, 100)

Fraction(Decimal('1.13'))
# returns Fraction(113, 100)

Bạn cũng có thể thực hiện các phép toán toán học đơn giản như cộng và trừ trên các phân số giống như số bình thường.

from fractions import Fraction

Fraction(113, 100) + Fraction(25, 18)
# returns Fraction(2267, 900)

Fraction(18, 5) / Fraction(18, 10)
# returns Fraction(2, 1)

Fraction(18, 5) * Fraction(16, 19)
# returns Fraction(288, 95)

Fraction(18, 5) * Fraction(15, 36)
# returns Fraction(3, 2)

Fraction(12, 5) ** Fraction(12, 10)
# returns 2.8592589556010197

Mô-đun này cũng có một vài phương thức quan trọng như

import decimal
from decimal import Decimal, getcontext

Decimal(1) / Decimal(13)
# returns Decimal('0.07692307692307692307692307692')

getcontext().prec = 10

Decimal(0.03)
# returns Decimal('0.02999999999999999888977697537')

Decimal(1) / Decimal(7)
# returns Decimal('0.1428571429')

getcontext().rounding = decimal.ROUND_DOWN

Decimal(1) / Decimal(7)
# returns Decimal('0.1428571428')

0 sẽ tìm và trả về một phân số gần nhất với giá trị của một phân số nhất định có mẫu số lớn nhất là
import decimal
from decimal import Decimal, getcontext

Decimal(1) / Decimal(13)
# returns Decimal('0.07692307692307692307692307692')

getcontext().prec = 10

Decimal(0.03)
# returns Decimal('0.02999999999999999888977697537')

Decimal(1) / Decimal(7)
# returns Decimal('0.1428571429')

getcontext().rounding = decimal.ROUND_DOWN

Decimal(1) / Decimal(7)
# returns Decimal('0.1428571428')

1. Bạn cũng có thể trả về tử số của một phân số nhất định trong giới hạn thấp nhất bằng cách sử dụng thuộc tính
import decimal
from decimal import Decimal, getcontext

Decimal(1) / Decimal(13)
# returns Decimal('0.07692307692307692307692307692')

getcontext().prec = 10

Decimal(0.03)
# returns Decimal('0.02999999999999999888977697537')

Decimal(1) / Decimal(7)
# returns Decimal('0.1428571429')

getcontext().rounding = decimal.ROUND_DOWN

Decimal(1) / Decimal(7)
# returns Decimal('0.1428571428')

2 và mẫu số bằng cách sử dụng thuộc tính
import decimal
from decimal import Decimal, getcontext

Decimal(1) / Decimal(13)
# returns Decimal('0.07692307692307692307692307692')

getcontext().prec = 10

Decimal(0.03)
# returns Decimal('0.02999999999999999888977697537')

Decimal(1) / Decimal(7)
# returns Decimal('0.1428571429')

getcontext().rounding = decimal.ROUND_DOWN

Decimal(1) / Decimal(7)
# returns Decimal('0.1428571428')

3.

from fractions import Fraction

Fraction('3.14159265358979323846')
# returns Fraction(157079632679489661923, 50000000000000000000)

Fraction('3.14159265358979323846').limit_denominator(10000)
# returns Fraction(355, 113)

Fraction('3.14159265358979323846').limit_denominator(100)
# returns Fraction(311, 99)

Fraction('3.14159265358979323846').limit_denominator(10)
# returns Fraction(22, 7)

Fraction(125, 50).numerator
# returns 5

Fraction(125, 50).denominator
# returns 2

Bạn cũng có thể sử dụng mô-đun này với các hàm khác nhau trong mô-đun math để thực hiện các phép tính dựa trên phân số.

import math
from fractions import Fraction

math.sqrt(Fraction(25, 4))
# returns 2.5

math.sqrt(Fraction(28,3))
# returns 3.0550504633038935

math.floor(Fraction(3558, 1213))
# returns 2

Fraction(math.sin(math.pi/3))
# returns Fraction(3900231685776981, 4503599627370496)

Fraction(math.sin(math.pi/3)).limit_denominator(10)
# returns Fraction(6, 7)

Tóm tắt

Hai mô-đun này chắc là đủ để giúp bạn thực hiện các phép toán thông thường trên cả số thập phân và phân số. Như trình bày trong phần cuối, bạn có thể sử dụng các mô-đun này cùng với mô-đun math để tính toán giá trị của tất cả các kiểu hàm toán học theo định dạng mà bạn mong muốn.

Trong hướng dẫn tiếp theo của loạt bài này, bạn sẽ được tìm hiểu về mô-đun random trong Python.