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
Dấu phẩy động là một kiểu đơn giản được tích hợp sẵn do Python cung cấp. Nó được gọi là kiểu đơn giản trái ngược với một số kiểu phức hợp như danh sách, tuple, dict và set. Số dấu phẩy động có thể lưu trữ các số phân số. Nó có thể được xác định trong ký hiệu thập phân tiêu chuẩn hoặc ký hiệu hàm mũ
máy tính. nhà phát triển
Ký hiệu thập phân chuẩn và ký hiệu hàm mũ
Trong ký hiệu số mũ, có thể đọc e
hoặc E
". lần mười đến. ", do đó 1.4e6
được hiểu là 1. 4×10^6
Một số nguyên có thể được chuyển đổi rõ ràng thành số float với hàm tạo float
Bây giờ chúng ta đã biết biểu diễn dấu phẩy động trong python, hãy chuyển sang một số lỗi Độ chính xác của dấu phẩy động
Bình đẳng không ổn định
thận trọng. Độ chính xác số học của dấu phẩy động bị hạn chế. *, điều này có thể khiến các bài kiểm tra đẳng thức không ổn định. Ví dụ
* Độ chính xác số học của dấu phẩy động bị hạn chế. Tại sao điều này là trường hợp? . Tất cả các ngôn ngữ lập trình sử dụng số dấu phẩy động lưu trữ chúng trong một số bit cố định và điều này dẫn đến một số số chỉ được biểu diễn gần đúng. Chúng ta có thể thấy điều này bằng cách in ba giá trị với độ chính xác cao
Chúng ta thường thấy các số ở dạng ký hiệu thập phân [cơ số 10], sao cho mỗi phân số được biểu diễn dưới dạng tổng các lũy thừa của 10
Đại diện cơ sở 10
Trên đây là biểu diễn cơ số 10, chúng tôi biểu diễn điều này trong biểu thức thập phân là. 0. 125
Máy tính thường lưu trữ các giá trị trong ký hiệu nhị phân, do đó mỗi số được biểu thị dưới dạng tổng lũy thừa của 2
Đại diện cơ sở 2
Trong biểu diễn cơ số 2, chúng ta có thể viết 0 này. 001, Giá trị 0. 125=0. 001 xảy ra là một số mà cả ký hiệu nhị phân và thập phân đều có thể biểu thị bằng một số chữ số hữu hạn
Trong biểu diễn cơ số 10 của các số, có lẽ bạn đã quen thuộc với các số không thể biểu thị bằng một số hữu hạn chữ số. Ví dụ: chia 1 cho 3, theo ký hiệu thập phân chuẩn
Thương số vô hạn cho ký hiệu thập phân
3s kéo dài mãi mãi. nghĩa là, vô số chữ số được yêu cầu để thực sự đại diện cho thương số này
Tương tự, có những số mà biểu diễn nhị phân yêu cầu vô số chữ số. Ví dụ
Thương số vô hạn cho ký hiệu nhị phân
Giống như ký hiệu thập phân yêu cầu vô số chữ số để biểu thị hoàn hảo 1/3, ký hiệu nhị phân yêu cầu vô số chữ số để biểu thị 1/10. Python nội bộ cắt bớt các biểu diễn này ở 52 bit ngoài bit khác không đầu tiên trên hầu hết các hệ thống. Cách tốt nhất để giải quyết vấn đề này là luôn ghi nhớ rằng số học dấu phẩy động là gần đúng và không bao giờ dựa vào các phép kiểm tra đẳng thức chính xác với các giá trị dấu phẩy động
Lỗi làm tròn chính xác
Nếu chúng ta cố gắng làm tròn giá trị 2. 675 đến hai chữ số thập phân chúng tôi nhận được. 2. 67
Tài liệu về hàm tích hợp nói rằng nó làm tròn đến giá trị gần nhất, làm tròn các mối quan hệ từ 0. Vì phân số thập phân 2. 675 chính xác nằm giữa 2. 67 và 2. 68, bạn có thể mong đợi kết quả ở đây là 2. 68. Không phải đâu, vì khi chuỗi thập phân 2. 675 được chuyển đổi thành số dấu phẩy động nhị phân, nó lại được thay thế bằng xấp xỉ nhị phân, có giá trị chính xác là,
Vì xấp xỉ này hơi gần với 2. 67 so với 2. 68, nó được làm tròn xuống
Một giải pháp để xử lý sự không nhất quán này trong giá trị dấu phẩy động là sử dụng mô-đun Python gốc có tên Decimal
Mô-đun thập phân
Sử dụng Decimal, chúng ta có thể thấy giá trị chính xác được lưu trữ trong bất kỳ float Python nào
Bạn cần cẩn thận khi sử dụng các giá trị Decimal[] với kiểu float sẵn có, trừ khi được xử lý đúng cách, nó sẽ dẫn đến lỗi Loại
Nhập lỗi khi thêm giá trị Decimal[] và giá trị float
quantize[] để giải quyết Lỗi làm tròn chính xác
Làm tròn dấu phẩy động bằng cách sử dụng quantize[] và round[]
normalize[] để ánh xạ các biểu diễn dấu phẩy động khác nhau thành một biểu diễn duy nhất
Một số ứng dụng có thể muốn có độ chính xác cố định cho tất cả các phép tính số học. Điều này có thể đạt được bằng cách sử dụng getcontext[]. prec, điều này sẽ hạn chế các vị trí chính xác lên đến các giá trị đã đặt [giá trị chính xác mặc định là 28]
Phần kết luận
Lỗi làm tròn đối với các giá trị dấu phẩy động là một lỗi cần thiết khi làm việc với các số dấu phẩy động. Do đó, chúng ta sẽ không bao giờ quên thực tế rằng các số dấu phẩy động là giá trị gần đúng nhưng không phải là giá trị chính xác.