Phao Python chính xác đến mức nào?

Trong các ngôn ngữ lập trình như JavaScript hoặc Python, các số thường được biểu diễn bằng các loại số IEEE 64 bit [binary64]. Đối với những con số này, chúng tôi có 15 chữ số chính xác. Điều đó có nghĩa là bạn có thể chọn một số có 15 chữ số, chẳng hạn như 1. 23456789012345e100 và nó có thể được biểu diễn chính xác. tồn tại một số dấu phẩy động có chính xác 15 chữ số quan trọng nhất này. Trong trường hợp cụ thể này, đó là số 6355009312518497 * 2280. Có độ chính xác 15 chữ số là tuyệt vời. một số quy trình kỹ thuật có thể vượt quá độ chính xác này

Độ chính xác 15 chữ số này không thành công đối với các số nằm ngoài phạm vi hợp lệ. Ví dụ: số 1e500 quá lớn và không thể được biểu diễn trực tiếp bằng số dấu phẩy động 64 bit tiêu chuẩn. Tương tự, 1e-500 quá nhỏ và nó chỉ có thể được biểu thị bằng 0

Phạm vi của số dấu phẩy động 64 bit có thể được định nghĩa là đi từ 4. 94e-324 đến 1. 8e308 và -1. 8e308 đến -4. 94e-324, cùng với chính xác 0. Tuy nhiên, phạm vi này bao gồm các số không bình thường trong đó độ chính xác tương đối có thể nhỏ. Ví dụ, số 5. 00000000000000e-324 được biểu diễn tốt nhất là 4. 94065645841247e-324, nghĩa là chúng tôi có độ chính xác bằng 0

Để quy tắc chính xác 15 chữ số hoạt động, bạn có thể duy trì ở phạm vi bình thường, e. g. , từ 2. 225e−308 đến 1. 8e308 và -1. 8e308 đến -2. 225e−308. Có những lý do chính đáng khác để duy trì trong phạm vi bình thường, chẳng hạn như hiệu suất kém và độ chính xác thấp trong phạm vi dưới mức bình thường

Tóm lại, các số dấu phẩy động tiêu chuẩn có độ chính xác tuyệt vời [ít nhất 15 chữ số] miễn là bạn vẫn ở trong phạm vi bình thường của chúng, nằm trong khoảng từ 2. 225e−308 đến 1. 8e308 cho số dương

Điều này thực sự dễ dàng, và tâm trí của bạn trong giai đoạn suy nghĩ đầu tiên có thể ngay lập tức đưa ra câu trả lời. Một và hai là ba, vì vậy một phần mười cộng với hai phần mười phải cộng lại bằng ba phần mười. Tất nhiên, điều này là chính xác và chúng ta có thể chứng minh điều đó bằng biểu thức toán học sau

0.1 + 0.2 == .3

Vì vậy, phép toán này chắc chắn là đúng, nhưng điều thú vị là điều gì sẽ xảy ra khi chúng ta làm điều tương tự bằng cách sử dụng kiểu dữ liệu float trong Python. Đây là phép toán tương tự được đưa vào Python REPL

[hình ảnh của tác giả]
0.1 + 0.20.30000000000000004

Tất nhiên, chúng tôi biết chắc chắn rằng điều này không đúng. Bộ não của chúng ta có thể dễ dàng phân biệt rằng

0.1 + 0.2 == .3
0.1 + 0.2 != 0.30000000000000004

Nhưng rõ ràng máy tính dường như nghĩ rằng nó có. Chúng tôi thấy rằng nếu chúng tôi đặt hai câu lệnh này vào Python REPL của mình, chúng tôi sẽ thấy rằng cả hai đều sai

[hình ảnh của tác giả]

Chuyện gì đang xảy ra ở đây vậy?

Chút ít

Để hiểu tại sao máy tính của chúng ta có thể gặp sự cố với phép tính đơn giản này, chúng ta cần xem xét cách máy tính lưu trữ số float. Tùy thuộc vào hệ thống và cài đặt của bạn, Python có thể đang lưu trữ chữ ký ba mươi hai bit hoặc sáu mươi tư bit cho số float của bạn. Chúng tôi sẽ giả định rằng kiến ​​trúc của hầu hết các hệ thống của trình đọc có thể không phải là i386, mà tôi nghĩ đó là một giả định hợp lệ và hầu hết các trình đọc có thể có hệ thống 64 bit

Có một cách chúng ta thực sự có thể thấy các bit được sử dụng để lưu trữ dữ liệu của chúng ta trong Python và đây là phương pháp tôi sẽ sử dụng để chứng minh chính xác nguyên nhân gây ra lỗi thao tác của chúng ta. Tôi sẽ làm điều này bằng cách sử dụng mô-đun cấu trúc. Mô-đun cấu trúc có phương thức pack[] nhận hai đối số. Đối số đầu tiên sẽ giải thích loại chúng tôi muốn đóng gói. Đối với điều này, tôi sẽ sử dụng “>d”. Biểu tượng lớn hơn được sử dụng để thể hiện cách viết toán học của con người, big-endian. d dành cho float-64 kép, độ chính xác kép. Chúng ta hãy xem các bit từ bản in của tất cả các số chúng ta vừa xem

>>> o1 = struct.pack[">d", .1]
>>> o2 = struct.pack[">d", .2]
>>> o3 = struct.pack[">d", .3]
>>> print["".join[f"{w:08b}" for w in o1]]
0011111110111001100110011001100110011001100110011001100110011010
>>> print["".join[f"{w:08b}" for w in o2]]
0011111111001001100110011001100110011001100110011001100110011010
>>> print["".join[f"{w:08b}" for w in o3]]
0011111111010011001100110011001100110011001100110011001100110011
>>>

Bây giờ, hãy chia nhỏ các bộ bit này xuống một chút, sử dụng 0. 1 làm ví dụ. Bit đầu tiên là bit dấu, có nghĩa là nó xác định tính tích cực của số của chúng ta, 0 cho số dương, 1 cho số âm. Tiếp theo là 11 bit được sử dụng làm số mũ trong công thức mà máy tính sử dụng để biểu thị số float của chúng ta. Điều này hoạt động rất giống ký hiệu khoa học. Hãy chia nhỏ hai giá trị đó bằng cách sử dụng vòng lặp nhanh

>>> bits = "".join[f"{w:08b}" for w in o1]
>>> count = 0
>>> signbit = []
>>> exponenetbits = []
>>> fractionalbits = []
>>> for bit in bits:
.. count += 1
.. if count == 1:
.. signbit.append[bit]
.. if count > 1 and count < 13:
.. exponenetbits.append[bit]
.. if count > 12:
.. fractionalbits.append[bit]

Bây giờ hãy in từng phần ra theo thứ tự. Và đừng hỏi tại sao tôi gõ nhầm “exonenet…” Tôi cũng không biết chuyện gì đã xảy ra

>>> print[signbit]
['0']
>>> print[exponentbits]
Traceback [most recent call last]:
File "", line 1, in
NameError: name 'exponentbits' is not defined
>>> print[exponenetbits]
['0', '1', '1', '1', '1', '1', '1', '1', '0', '1', '1']
>>> print[fractionalbits]
['1', '0', '0', '1', '1', '0', '0', '1', '1', '0', '0', '1', '1', '0', '0', '1', '1', '0', '0', '1', '1', '0', '0', '1', '1', '0', '0', '1', '1', '0', '0', '1', '1', '0', '0', '1', '1', '0', '0', '1', '1', '0', '0', '1', '1', '0', '0', '1', '1', '0', '1', '0']
>>>

Có, tôi đã cố gắng gõ số mũ. Chúng tôi cắm các giá trị này vào công thức sau

[-1] ^ ký * 2^e-1023 * 1. phân số

Trong công thức này, bất cứ khi nào chúng ta cộng một phần mười và hai phần mười, số thập phân của chúng ta sẽ bị cắt và làm tròn tại một số điểm. Điều đó giải thích tại sao hiện tượng này xảy ra, do lỗi làm tròn đơn giản

Phần kết luận

Chúng tôi thích nghĩ về máy tính cực kỳ thông minh và rất chính xác, nhưng đơn giản là không phải vậy. Vào cuối ngày, việc hiểu cách máy tính hoạt động ở cấp độ này thực sự sẽ chứng minh tại sao máy tính mắc các lỗi đơn giản như thế này. Vào cuối ngày, nó vẫn là một hệ thống unicode và bit phức tạp hoạt động cùng nhau để tạo ra các biểu thức mà chúng ta viết. Cảm ơn bạn đã đọc bài viết này và tôi hy vọng bạn đã học được điều gì đó mới về đánh đôi

Làm thế nào chính xác là một phao?

Số float có độ chính xác đơn chỉ có khoảng 7 chữ số thập phân có độ chính xác [thực tế là cơ số nhật ký 10 của 223 hoặc khoảng 6. 92 chữ số chính xác]. Phần nguyên càng lớn thì càng ít khoảng trống cho độ chính xác của phần nổi.

Tại sao các dấu phẩy động không chính xác trong Python?

Các phép tính dấu phẩy động không chính xác vì chủ yếu là các số hữu tỉ là xấp xỉ không thể biểu diễn hữu hạn trong cơ số 2 và nói chung chúng là xấp xỉ .

Là phao không chính xác?

Các giá trị thập phân có dấu phẩy động thường không có biểu diễn nhị phân chính xác. Đây là tác dụng phụ của cách CPU biểu thị dữ liệu dấu chấm động. Vì lý do này, bạn có thể bị mất độ chính xác đôi chút và một số thao tác dấu phẩy động có thể tạo ra kết quả không mong muốn.

Bao nhiêu độ chính xác là một phao?

float là Số dấu phẩy động chính xác đơn IEEE 754 32 bit – 1 bit cho dấu, 8 bit cho số mũ và 23* cho giá trị. float có 7 chữ số thập phân chính xác.

Chủ Đề