Python có thể float đại diện cho 0,1 mà không có lỗi không?

Đây có thể được coi là một lỗi trong Python, nhưng không phải vậy. Điều này ít liên quan đến Python và liên quan nhiều hơn đến cách nền tảng cơ bản xử lý các số dấu phẩy động. Đó là trường hợp bình thường gặp phải khi xử lý các số dấu phẩy động bên trong hệ thống. Đó là sự cố xảy ra khi biểu diễn bên trong các số dấu phẩy động, sử dụng một số chữ số nhị phân cố định để biểu thị một số thập phân. Rất khó để biểu diễn một số thập phân dưới dạng nhị phân nên trong nhiều trường hợp dẫn đến sai số làm tròn nhỏ

Chúng ta biết những trường hợp tương tự trong toán thập phân, có nhiều kết quả không thể biểu diễn bằng một số chữ số thập phân cố định,
Thí dụ

10 / 3 = 3.33333333.......

Trong trường hợp này, lấy 1. 2 làm ví dụ, biểu diễn của 0. 2 ở dạng nhị phân là0.00110011001100110011001100......, v.v.
Rất khó để lưu trữ nội bộ số thập phân vô hạn này. Thông thường, giá trị của đối tượng float được lưu trữ ở dạng dấu phẩy động nhị phân với độ chính xác cố định [thường là 53 bit]

Vì vậy, chúng tôi đại diện cho 1. 2 nội bộ như,

1.0011001100110011001100110011001100110011001100110011  

Đó là chính xác bằng

1.1999999999999999555910790149937383830547332763671875

Tuy nhiên, bạn đang nghĩ tại sao python không giải quyết được vấn đề này, thực ra nó không liên quan gì đến python. Nó xảy ra bởi vì đó là cách nền tảng c bên dưới xử lý các số có dấu phẩy động và cuối cùng với sự không chính xác, chúng tôi sẽ luôn viết các số dưới dạng một chuỗi các chữ số cố định

Bạn đã bao giờ gặp phải các vấn đề kỳ lạ khi làm việc với các số dấu phẩy động - chẳng hạn như khi thực hiện thao tác nào đó như sau?

a = 10b = 0.1c = 0.2a*[b+c] == a*b + a*c # This will print False

Đợi đã, cái gì?

Hãy xem một ví dụ khác

>>> .2 + .2 + .2 == .6False

Hoặc hãy xem vòng lặp này - nó sẽ chạy vô thời hạn

foo = 0while foo != 1.0:    foo = foo + 0.1print[foo]

Chuyện Gì Đang Xảy Ra?

TL; DR — Số dấu phẩy động thật kỳ lạ

Số dấu phẩy động hoạt động khá kỳ lạ trên các hệ thống nhị phân. Do đó, điều quan trọng là bạn nhận thức được hành vi này. Tôi sẽ giúp bạn tránh những sai lầm đơn giản có thể bỏ qua, chẳng hạn như một vòng lặp vô tận hoặc chỉ so sánh cơ bản

Khi làm việc với số thập phân trong Python, chúng ta thường chuyển sang số float. Phao nổi phục vụ chúng tôi tốt cho hầu hết các mục đích, chẳng hạn như phân chia đơn giản, nhưng chúng có những hạn chế có thể trở thành vấn đề cực kỳ nghiêm trọng đối với một số trường hợp sử dụng nhất định. Đơn giản là chúng không đủ chính xác. Tuy nhiên, float không phải là lựa chọn duy nhất của chúng ta, và hôm nay chúng ta sẽ xem xét mô-đun

a = 10
b = a / 77
c = b * 77

if a != c:
    print["Things got weird..."]

# Things got weird...
6 và lý do tại sao bạn có thể sử dụng nó

Nhìn nhanh vào nhị phân

Trước khi chúng ta có thể hiểu đúng vấn đề với số float, chúng ta cần xem xét nhanh cách các số được biểu thị trong hệ nhị phân

Hệ thống số mà chúng ta sử dụng trong cuộc sống hàng ngày là hệ thống số cơ số 10, còn được gọi là hệ thống số thập phân. Chúng tôi sử dụng mười chữ số duy nhất trong các kết hợp khác nhau để đại diện cho tất cả các số. Mặt khác, nhị phân là một hệ thống số cơ sở 2 và chỉ sử dụng hai chữ số duy nhất. nói chung là 0 và 1. Khi các số được lưu trữ trong máy tính của chúng tôi, chúng được lưu trữ ở định dạng nhị phân này

Một số nhị phân có thể trông giống như thế này. 10101101, tức là 173

Vậy làm thế nào để chúng ta có được 173 trên 10101101?

Nhị phân hoạt động ở lũy thừa 2, vì vậy số 1 ngoài cùng bên phải trong 10101101, đại diện cho 1 x 2⁰. Sau đó, chúng tôi đi một bước sang trái, nơi chúng tôi tìm thấy số 0. Số 0 này đại diện cho 0 x 2¹, là 0 x 2. Bước thêm một bước sang trái và chúng tôi tìm thấy một số 1 khác, lần này đại diện cho 1 x 2², tức là 4. Mỗi bước sang trái, sức mạnh tăng thêm 1

Tổng cộng chúng ta có một cái gì đó trông như thế này

[1 × 2⁷] + [0 × 2⁶] + [1 × 2⁵] + [0 × 2⁴] + [1 × 2³] + [1 × 2²] + [0 × 2¹] + [1 × 2⁰]

Đó là

[1 x 128] + [0 x 64] + [1 x 32] + [0 x 16] + [1 x 8] + [1 x 4] + [0 x 2] + [1 x 1]

Nếu chúng tôi cộng tất cả những thứ này lại, chúng tôi sẽ nhận được 173. Như bạn có thể thấy, biểu diễn nhị phân của các số có xu hướng dài hơn nhiều so với biểu diễn thập phân, nhưng cuối cùng chúng ta có thể biểu diễn bất kỳ số nguyên nào theo cách này

Phân số trong nhị phân

Vì vậy, chúng tôi đã thực hiện ôn tập nhanh về cách các số nguyên có thể được biểu diễn dưới dạng nhị phân, nhưng còn phân số thì sao?

Ví dụ: 2⁻¹ là ½ và 2⁻² là ¼, có nghĩa là bây giờ chúng ta có thể đại diện cho 0. 75, 0. 5 và 0. 25. Sử dụng các lũy thừa âm lớn hơn dần dần, chúng ta có thể biểu diễn tất cả các cách của số thập phân

Tuy nhiên, cũng như có những số chúng ta không thể biểu diễn bằng một số hữu hạn các chữ số thập phân [e. g. ⅓], cũng có những số chúng ta không thể biểu diễn dưới dạng nhị phân. Ví dụ, số 0. 1 không có đại diện nhị phân hữu hạn

Nổi trong Python

Vậy điều gì sẽ xảy ra khi chúng ta viết

a = 10
b = a / 77
c = b * 77

if a != c:
    print["Things got weird..."]

# Things got weird...
7 bằng Python?

________số 8_______

Đối với những bạn chưa quen với cú pháp trên, thì ____6_______8 là một cách để nói với Python rằng chúng tôi muốn 20 chữ số sau dấu thập phân cho số float này. Chúng tôi có một bài đăng bạn có thể xem bên dưới

https. //Blog. mật mã. com/python-formatting-number-for-printing/

Như chúng ta có thể thấy, chúng ta không thực sự nhận được

a = 10
b = a / 77
c = b * 77

if a != c:
    print["Things got weird..."]

# Things got weird...
7. chúng tôi nhận được một xấp xỉ gần đúng của
a = 10
b = a / 77
c = b * 77

if a != c:
    print["Things got weird..."]

# Things got weird...
7. Thật không may, đôi khi một phép tính gần đúng không đủ tốt

Điều này đặc biệt phổ biến khi thực hiện so sánh

a = 10
b = a / 77
c = b * 77

if a != c:
    print["Things got weird..."]

# Things got weird...

Nếu chúng ta in

print[f"{a:.20f}"]  # 10.00000000000000000000
print[f"{c:.20f}"]  #  9.99999999999999822364
1 và
print[f"{a:.20f}"]  # 10.00000000000000000000
print[f"{c:.20f}"]  #  9.99999999999999822364
2, chúng ta có thể thấy điều gì đã xảy ra

print[f"{a:.20f}"]  # 10.00000000000000000000
print[f"{c:.20f}"]  #  9.99999999999999822364

Lỗi gần đúng này có thể trở nên phức tạp hơn rất nhiều trong một loạt các hoạt động, có nghĩa là chúng ta thực sự có thể nhận được sự khác biệt khá đáng kể giữa các số giống hệt nhau

Bạn có thể đọc thêm về những vấn đề này trong tài liệu Python. https. // tài liệu. con trăn. org/3/hướng dẫn/dấu phẩy động. html

Nhập
a = 10
b = a / 77
c = b * 77

if a != c:
    print["Things got weird..."]

# Things got weird...
6

Như đã đề cập ở đầu bài viết này, Python có một cách khác để xử lý các số thập phân, đó là mô-đun

a = 10
b = a / 77
c = b * 77

if a != c:
    print["Things got weird..."]

# Things got weird...
6. Không giống như số float, các đối tượng
print[f"{a:.20f}"]  # 10.00000000000000000000
print[f"{c:.20f}"]  #  9.99999999999999822364
5 được xác định trong mô-đun
a = 10
b = a / 77
c = b * 77

if a != c:
    print["Things got weird..."]

# Things got weird...
6 không dễ bị mất độ chính xác này, bởi vì chúng không dựa vào phân số nhị phân

Tạo
print[f"{a:.20f}"]  # 10.00000000000000000000
print[f"{c:.20f}"]  #  9.99999999999999822364
5 đối tượng

Trước khi chúng ta đi sâu vào các đối tượng

print[f"{a:.20f}"]  # 10.00000000000000000000
print[f"{c:.20f}"]  #  9.99999999999999822364
5, hãy xem cách xác định chúng. Thực tế có một số cách để làm điều này

Sử dụng một số nguyên

Cách đầu tiên để tạo một đối tượng

print[f"{a:.20f}"]  # 10.00000000000000000000
print[f"{c:.20f}"]  #  9.99999999999999822364
5 chúng ta sử dụng một số nguyên. Trong trường hợp này, chúng ta chỉ cần chuyển số nguyên làm đối số cho hàm tạo
print[f"{a:.20f}"]  # 10.00000000000000000000
print[f"{c:.20f}"]  #  9.99999999999999822364
5

import decimal

x = decimal.Decimal[34]  # 34

Bây giờ chúng ta có thể sử dụng

import decimal

x = decimal.Decimal[34]  # 34
1 giống như bất kỳ số nào khác và chúng ta sẽ nhận lại một đối tượng
print[f"{a:.20f}"]  # 10.00000000000000000000
print[f"{c:.20f}"]  #  9.99999999999999822364
5 khi thực hiện các phép toán

x = decimal.Decimal[34]

print[x + 7]         # 41
print[type[x + 7]]   # 

print[x // 7]        # 4
print[type[x // 7]]  # 

Sử dụng một chuỗi

Có lẽ hơi ngạc nhiên một chút, một trong những cách dễ nhất để tạo một đối tượng

print[f"{a:.20f}"]  # 10.00000000000000000000
print[f"{c:.20f}"]  #  9.99999999999999822364
5 với các thành phần phân số là sử dụng một chuỗi. Chúng ta chỉ cần chuyển một chuỗi đại diện của số tới
print[f"{a:.20f}"]  # 10.00000000000000000000
print[f"{c:.20f}"]  #  9.99999999999999822364
5 và nó sẽ lo phần còn lại

x = decimal.Decimal["0.1"]

print[x]            # 0.1
print[f"{x:.20f}"]  # 0.10000000000000000000

Như chúng ta có thể thấy, in

import decimal

x = decimal.Decimal[34]  # 34
1 đến 20 chữ số thập phân ở đây cho chúng ta 19 chữ số 0. chúng tôi không kết thúc với một số 5 ngẫu nhiên ở cuối như chúng tôi đã làm khi sử dụng float

Nếu bạn cần một biểu diễn thập phân chính xác của một số, sử dụng các chuỗi để tạo các đối tượng

print[f"{a:.20f}"]  # 10.00000000000000000000
print[f"{c:.20f}"]  #  9.99999999999999822364
5 của bạn là một cách rất đơn giản để đạt được điều này

Sử dụng phao

Cũng có thể tạo một đối tượng

print[f"{a:.20f}"]  # 10.00000000000000000000
print[f"{c:.20f}"]  #  9.99999999999999822364
5 từ một float, nhưng tôi thường khuyên bạn không nên làm điều này. Ví dụ dưới đây sẽ làm rõ lý do tại sao

x = decimal.Decimal[0.1]
print[x]  # 0.1000000000000000055511151231257827021181583404541015625

Việc chuyển đổi trực tiếp từ float khiến đối tượng

print[f"{a:.20f}"]  # 10.00000000000000000000
print[f"{c:.20f}"]  #  9.99999999999999822364
5 của chúng ta thừa hưởng tất cả sự thiếu chính xác mà chúng ta đã cố gắng tránh ngay từ đầu. Có thể có những trường hợp bạn muốn bảo vệ sự không chính xác này vì một lý do nào đó, nhưng hầu hết thời gian thì không phải như vậy.

Sử dụng một tuple

Có lẽ phương pháp phức tạp nhất để tạo một đối tượng

print[f"{a:.20f}"]  # 10.00000000000000000000
print[f"{c:.20f}"]  #  9.99999999999999822364
5 là sử dụng một tuple, và phương pháp này cho chúng ta một số hiểu biết sâu sắc về cách các đối tượng
print[f"{a:.20f}"]  # 10.00000000000000000000
print[f"{c:.20f}"]  #  9.99999999999999822364
5 hoạt động ngầm.

Bộ dữ liệu chúng tôi cung cấp cho

print[f"{a:.20f}"]  # 10.00000000000000000000
print[f"{c:.20f}"]  #  9.99999999999999822364
5 có ba phần. Phần tử đầu tiên trong bộ dữ liệu là số
x = decimal.Decimal[34]

print[x + 7]         # 41
print[type[x + 7]]   # 

print[x // 7]        # 4
print[type[x // 7]]  # 
2 hoặc
x = decimal.Decimal[34]

print[x + 7]         # 41
print[type[x + 7]]   # 

print[x // 7]        # 4
print[type[x // 7]]  # 
3 và phần tử này đại diện cho dấu của số [cho dù đó là số dương hay âm]. Số 0 ở vị trí đầu tiên này biểu thị số dương, trong khi số 1 biểu thị số âm

Mục thứ hai trong bộ dữ liệu là một bộ dữ liệu khác và bộ này chứa tất cả các chữ số trong số kết quả. Ví dụ: số

x = decimal.Decimal[34]

print[x + 7]         # 41
print[type[x + 7]]   # 

print[x // 7]        # 4
print[type[x // 7]]  # 
4 có các chữ số
x = decimal.Decimal[34]

print[x + 7]         # 41
print[type[x + 7]]   # 

print[x // 7]        # 4
print[type[x // 7]]  # 
5

Phần tử thứ ba và cũng là phần tử cuối cùng trong bộ dữ liệu là một số mũ. Điều này cho đối tượng

print[f"{a:.20f}"]  # 10.00000000000000000000
print[f"{c:.20f}"]  #  9.99999999999999822364
5 biết chúng ta cần dịch chuyển bao nhiêu vị trí các chữ số xung quanh dấu thập phân. Số mũ của
x = decimal.Decimal[34]

print[x + 7]         # 41
print[type[x + 7]]   # 

print[x // 7]        # 4
print[type[x // 7]]  # 
7 sẽ làm cho các chữ số dịch chuyển 3 dấu cách sang bên phải, cho chúng ta
x = decimal.Decimal[34]

print[x + 7]         # 41
print[type[x + 7]]   # 

print[x // 7]        # 4
print[type[x // 7]]  # 
8, trong khi số mũ của
x = decimal.Decimal[34]

print[x + 7]         # 41
print[type[x + 7]]   # 

print[x // 7]        # 4
print[type[x // 7]]  # 
9 sẽ cho chúng ta
x = decimal.Decimal["0.1"]

print[x]            # 0.1
print[f"{x:.20f}"]  # 0.10000000000000000000
0

Một ví dụ hoàn chỉnh cho số

x = decimal.Decimal["0.1"]

print[x]            # 0.1
print[f"{x:.20f}"]  # 0.10000000000000000000
1 trông như thế này

x = decimal.Decimal[[1, [1, 3, 0, 4, 2], -3]]
print[x]  # -13.042

Một điều thực sự quan trọng cần lưu ý ở đây là chúng ta cần các dấu ngoặc quanh bộ bên ngoài, vì

print[f"{a:.20f}"]  # 10.00000000000000000000
print[f"{c:.20f}"]  #  9.99999999999999822364
5 mong đợi bộ này là một đối số duy nhất. Xóa dấu ngoặc ngoài sẽ gây ra lỗi

Mặc dù tương đối phức tạp nhưng cú pháp tuple phù hợp nhất để tạo các đối tượng

print[f"{a:.20f}"]  # 10.00000000000000000000
print[f"{c:.20f}"]  #  9.99999999999999822364
5 theo cách lập trình

Đối tượng
x = decimal.Decimal["0.1"]

print[x]            # 0.1
print[f"{x:.20f}"]  # 0.10000000000000000000
4

Một trong những điều thú vị về mô-đun

a = 10
b = a / 77
c = b * 77

if a != c:
    print["Things got weird..."]

# Things got weird...
6 là nó cho phép chúng ta xác định hành vi của các đối tượng
print[f"{a:.20f}"]  # 10.00000000000000000000
print[f"{c:.20f}"]  #  9.99999999999999822364
5 theo nhiều cách khác nhau. Chúng tôi có thể chỉ định mức độ chính xác, giới hạn cho số mũ và thậm chí cả quy tắc làm tròn

Để làm điều này, chúng ta thường sẽ làm việc với hàm

x = decimal.Decimal["0.1"]

print[x]            # 0.1
print[f"{x:.20f}"]  # 0.10000000000000000000
7, cho phép chúng ta xem và sửa đổi đối tượng
x = decimal.Decimal["0.1"]

print[x]            # 0.1
print[f"{x:.20f}"]  # 0.10000000000000000000
4 cho luồng hiện tại

Chúng ta hãy xem một đối tượng

x = decimal.Decimal["0.1"]

print[x]            # 0.1
print[f"{x:.20f}"]  # 0.10000000000000000000
4 mặc định trông như thế nào

import decimal

print[decimal.getcontext[]]
# Context[prec=28, rounding=ROUND_HALF_EVEN, Emin=-999999, Emax=999999, capitals=1, clamp=0, flags=[], traps=[InvalidOperation, DivisionByZero, Overflow]]

Như bạn có thể thấy, chúng tôi có tất cả các loại thuộc tính mà chúng tôi có thể thiết lập để thay đổi cách hoạt động của đối tượng

print[f"{a:.20f}"]  # 10.00000000000000000000
print[f"{c:.20f}"]  #  9.99999999999999822364
5

Ví dụ: chúng tôi có thể quyết định rằng chúng tôi muốn độ chính xác có giá trị bằng 10 con số quan trọng, chúng tôi sẽ đặt như thế này

import decimal

decimal.getcontext[].prec = 10
x = decimal.Decimal[1] / decimal.Decimal[7]

print[x]  # 0.1428571429

Lưu ý rằng độ chính xác mới này chỉ phù hợp trong các phép toán. Chúng ta có thể định nghĩa một đối tượng

print[f"{a:.20f}"]  # 10.00000000000000000000
print[f"{c:.20f}"]  #  9.99999999999999822364
5 với độ chính xác tùy ý, ngay cả khi chúng ta đặt mức độ chính xác thấp hơn bằng cách sử dụng
x = decimal.Decimal["0.1"]

print[x]            # 0.1
print[f"{x:.20f}"]  # 0.10000000000000000000
7

a = 10
b = a / 77
c = b * 77

if a != c:
    print["Things got weird..."]

# Things got weird...
0

Như tôi đã đề cập trước đó, chúng ta cũng có thể xác định cách làm tròn hoạt động cho các đối tượng

print[f"{a:.20f}"]  # 10.00000000000000000000
print[f"{c:.20f}"]  #  9.99999999999999822364
5, điều này có thể rất hữu ích. Theo mặc định, Python sử dụng cách làm tròn của nhân viên ngân hàng, điều này hơi khác so với cách làm tròn mà chúng ta học ở trường

Chúng tôi nói về việc làm tròn của nhân viên ngân hàng ở đây nếu bạn chưa quen với nó. https. //Blog. mật mã. com/làm tròn trong trăn/

Sử dụng

x = decimal.Decimal["0.1"]

print[x]            # 0.1
print[f"{x:.20f}"]  # 0.10000000000000000000
7, chúng ta có thể thay đổi hành vi làm tròn của Python thành luôn làm tròn số thập phân kết thúc bằng
x = decimal.Decimal[0.1]
print[x]  # 0.1000000000000000055511151231257827021181583404541015625
5 cách xa
x = decimal.Decimal[34]

print[x + 7]         # 41
print[type[x + 7]]   # 

print[x // 7]        # 4
print[type[x // 7]]  # 
2, đó là cách chúng ta làm tròn trong cuộc sống hàng ngày

a = 10
b = a / 77
c = b * 77

if a != c:
    print["Things got weird..."]

# Things got weird...
1

Một số hành vi làm tròn khác nhau được xác định trong mô-đun

a = 10
b = a / 77
c = b * 77

if a != c:
    print["Things got weird..."]

# Things got weird...
6 bằng cách sử dụng các hằng số. Bạn có thể đọc thêm về các tùy chọn có sẵn tại đây.

Một số phương pháp
a = 10
b = a / 77
c = b * 77

if a != c:
    print["Things got weird..."]

# Things got weird...
6 hữu ích

Mô-đun

a = 10
b = a / 77
c = b * 77

if a != c:
    print["Things got weird..."]

# Things got weird...
6 đi kèm với một số phương pháp hữu ích để làm việc với các đối tượng
print[f"{a:.20f}"]  # 10.00000000000000000000
print[f"{c:.20f}"]  #  9.99999999999999822364
5. Dưới đây là một số mà bạn có thể muốn kiểm tra

x = decimal.Decimal[[1, [1, 3, 0, 4, 2], -3]]
print[x]  # -13.042
1

Phương pháp

x = decimal.Decimal[[1, [1, 3, 0, 4, 2], -3]]
print[x]  # -13.042
1 cho phép chúng tôi lấy căn bậc hai của bất kỳ
print[f"{a:.20f}"]  # 10.00000000000000000000
print[f"{c:.20f}"]  #  9.99999999999999822364
5 nào với mức độ chính xác được chỉ định

a = 10
b = a / 77
c = b * 77

if a != c:
    print["Things got weird..."]

# Things got weird...
2

x = decimal.Decimal[[1, [1, 3, 0, 4, 2], -3]]
print[x]  # -13.042
4

Phương thức

x = decimal.Decimal[[1, [1, 3, 0, 4, 2], -3]]
print[x]  # -13.042
4 được sử dụng để thay đổi một đối tượng
print[f"{a:.20f}"]  # 10.00000000000000000000
print[f"{c:.20f}"]  #  9.99999999999999822364
5 thành một số mũ mới. Ví dụ: giả sử chúng tôi có số
x = decimal.Decimal[[1, [1, 3, 0, 4, 2], -3]]
print[x]  # -13.042
7 và chúng tôi muốn thay đổi số này để khớp với mẫu
x = decimal.Decimal[[1, [1, 3, 0, 4, 2], -3]]
print[x]  # -13.042
8, chúng tôi có thể viết như sau

a = 10
b = a / 77
c = b * 77

if a != c:
    print["Things got weird..."]

# Things got weird...
3

Một điều cần lưu ý với phương pháp

x = decimal.Decimal[[1, [1, 3, 0, 4, 2], -3]]
print[x]  # -13.042
4 là nó sẽ đưa ra một ngoại lệ
import decimal

print[decimal.getcontext[]]
# Context[prec=28, rounding=ROUND_HALF_EVEN, Emin=-999999, Emax=999999, capitals=1, clamp=0, flags=[], traps=[InvalidOperation, DivisionByZero, Overflow]]
0 nếu các giá trị cuối cùng vượt quá mức độ chính xác đã xác định

a = 10
b = a / 77
c = b * 77

if a != c:
    print["Things got weird..."]

# Things got weird...
4

import decimal

print[decimal.getcontext[]]
# Context[prec=28, rounding=ROUND_HALF_EVEN, Emin=-999999, Emax=999999, capitals=1, clamp=0, flags=[], traps=[InvalidOperation, DivisionByZero, Overflow]]
1

Phương thức

import decimal

print[decimal.getcontext[]]
# Context[prec=28, rounding=ROUND_HALF_EVEN, Emin=-999999, Emax=999999, capitals=1, clamp=0, flags=[], traps=[InvalidOperation, DivisionByZero, Overflow]]
1 cung cấp cho chúng ta một đại diện bộ dữ liệu của đối tượng
print[f"{a:.20f}"]  # 10.00000000000000000000
print[f"{c:.20f}"]  #  9.99999999999999822364
5, giống như khi chúng ta tạo một bộ dữ liệu bằng cú pháp bộ dữ liệu

a = 10
b = a / 77
c = b * 77

if a != c:
    print["Things got weird..."]

# Things got weird...
5

Có nhiều phương pháp khác có sẵn cho đối tượng

print[f"{a:.20f}"]  # 10.00000000000000000000
print[f"{c:.20f}"]  #  9.99999999999999822364
5 và tôi khuyên bạn nên xem phần tài liệu này để tìm hiểu thêm.

Vì vậy, chúng ta chỉ nên sử dụng
a = 10
b = a / 77
c = b * 77

if a != c:
    print["Things got weird..."]

# Things got weird...
6?

Không cần thiết. Mặc dù mô-đun

a = 10
b = a / 77
c = b * 77

if a != c:
    print["Things got weird..."]

# Things got weird...
6 chắc chắn là rất gọn gàng và nó có lợi ích là độ chính xác tuyệt đối, nhưng độ chính xác này phải trả giá. Trong trường hợp này, chi phí là gấp đôi

Thứ nhất, sử dụng mô-đun

a = 10
b = a / 77
c = b * 77

if a != c:
    print["Things got weird..."]

# Things got weird...
6 khó hơn nhiều so với sử dụng float. Điều này là hiển nhiên ngay khi chúng ta nhìn vào đối tượng
import decimal

print[decimal.getcontext[]]
# Context[prec=28, rounding=ROUND_HALF_EVEN, Emin=-999999, Emax=999999, capitals=1, clamp=0, flags=[], traps=[InvalidOperation, DivisionByZero, Overflow]]
8 ở trên và chúng ta cũng có những thứ như bối cảnh để xem xét trên đầu trang này. Bạn chỉ cần biết nhiều hơn để thậm chí sử dụng mô-đun

Tuy nhiên, vấn đề thứ hai có lẽ cấp bách hơn, đó là hiệu suất. Các thao tác của

a = 10
b = a / 77
c = b * 77

if a != c:
    print["Things got weird..."]

# Things got weird...
6 có thể chậm hơn khoảng 3 lần so với các thao tác sử dụng float, vì vậy nếu bạn đang xử lý một phần nhạy cảm về hiệu suất trong ứng dụng của mình, trong đó độ chính xác tuyệt đối không quan trọng, bạn có thể muốn tránh sử dụng
a = 10
b = a / 77
c = b * 77

if a != c:
    print["Things got weird..."]

# Things got weird...
6. Điều này đặc biệt đúng nếu bạn vẫn đang làm việc với Python 2, vì các thao tác khi đó có thể chậm hơn vài trăm lần

Mô-đun

a = 10
b = a / 77
c = b * 77

if a != c:
    print["Things got weird..."]

# Things got weird...
6 là một công cụ tuyệt vời cần có trong bộ công cụ của chúng ta, nhưng chúng ta phải luôn biết liệu chúng ta có thực sự cần nó cho một ứng dụng cụ thể hay không

kết thúc

Đó là nó cho bài đăng này trên số float và số thập phân. Chắc chắn còn rất nhiều điều để tìm hiểu, vì vậy, một lần nữa, hãy xem tài liệu. Tài liệu về mô-đun

a = 10
b = a / 77
c = b * 77

if a != c:
    print["Things got weird..."]

# Things got weird...
6 có thể hơi đáng sợ, nhưng hy vọng rằng những gì chúng tôi đã nói ở đây sẽ giúp bạn chuẩn bị tốt để đi sâu vào

Nếu bạn thích các bài đăng của chúng tôi và bạn muốn đưa Python của mình lên một tầm cao mới, hãy nhớ xem Khóa học Python hoàn chỉnh của chúng tôi

có thể 0. 1 được thể hiện mà không có lỗi trong Python?

Bắt đầu với Python 3. 1, Python [trên hầu hết các hệ thống] hiện có thể chọn cái ngắn nhất trong số này và chỉ cần hiển thị 0. 1 . Lưu ý rằng đây là bản chất của dấu phẩy động nhị phân. đây không phải là lỗi trong Python và nó cũng không phải là lỗi trong mã của bạn.

Loại float có thể đại diện cho số thập phân 0. 1 mà không có lỗi?

Số 0. 1 trong dấu phẩy động . 0 0011 ‾ 0. 0\overline{0011} 0. 00011, nhưng nó không thể được biểu diễn ở dạng dấu phẩy động vì chúng ta không thể xử lý các thanh ở dạng dấu phẩy động . Chúng tôi chỉ có thể biểu diễn nó bằng các chữ số/bit cố định bằng bất kỳ loại dữ liệu nào.

số 0 được không. 1 được biểu diễn chính xác bằng cách sử dụng IEEE floating

Lý do bạn không thể đại diện cho 0. 1 dưới dạng số dấu phẩy động nhị phân cũng vì lý do chính xác như vậy. Bạn có thể đại diện chính xác cho 3, 9 và 27 - nhưng không phải là 1/3, 1/9 hoặc 1/27.

Tại sao 0. 1 0. 2 không phải là 0. 3 con trăn?

Tương tự, giá trị nhị phân của 0. 2 được lưu dưới dạng 0. 001100110. Bây giờ, khi bạn thêm 0. 1 + 0. 2 bằng Python [hoặc bằng một số ngôn ngữ lập trình khác], Python chuyển đổi 0. 1 và 0. 2 về dạng nhị phân. Sau đó, nó thực hiện phép cộng. Kết quả sẽ không bao giờ bằng 0. 3 chính xác .

Chủ Đề