Tại sao 0,1 0,2 không bằng 0,3 trong JavaScript?

Các số dấu phẩy động được biểu diễn, ở cấp độ phần cứng, dưới dạng phân số của các số nhị phân (cơ số 2). Ví dụ, phân số thập phân

0.125

có giá trị 1/10 + 2/100 + 5/1000 và theo cách tương tự, phân số nhị phân

0.001

có giá trị 0/2 + 0/4 + 1/8. Hai phân số này có cùng giá trị, chỉ khác là phân số thứ nhất là phân số thập phân, phân số thứ hai là phân số nhị phân

Thật không may, hầu hết các phân số thập phân không thể biểu diễn chính xác ở dạng phân số nhị phân. Do đó, nói chung, các số dấu phẩy động bạn đưa ra chỉ gần đúng với các phân số nhị phân được lưu trữ trong máy

Vấn đề dễ tiếp cận hơn trong cơ số 10. Lấy ví dụ, phân số 1/3. Bạn có thể ước tính nó thành một phần thập phân

0.3

hoặc tốt hơn,

0.33

hoặc tốt hơn,

0.333

vân vân. Cho dù bạn viết bao nhiêu chữ số thập phân, kết quả không bao giờ chính xác là 1/3, nhưng đó là ước tính luôn gần đúng hơn

Tương tự như vậy, bất kể bạn sử dụng bao nhiêu chữ số thập phân cơ số 2, giá trị thập phân 0. 1 không thể được biểu diễn chính xác dưới dạng phân số nhị phân. Trong cơ số 2, 1/10 là số tuần hoàn sau

0.0001100110011001100110011001100110011001100110011 ...

Dừng lại ở bất kỳ số lượng bit hữu hạn nào và bạn sẽ nhận được giá trị xấp xỉ

Đối với Python, trên một máy điển hình, 53 bit được sử dụng cho độ chính xác của số float, vì vậy giá trị được lưu trữ khi bạn nhập số thập phân 0. 1 là phân số nhị phân

0.00011001100110011001100110011001100110011001100110011010

gần, nhưng không chính xác bằng, đến 1/10

Thật dễ dàng để quên rằng giá trị được lưu trữ là giá trị gần đúng của phần thập phân ban đầu, do cách hiển thị số float trong trình thông dịch. Python chỉ hiển thị xấp xỉ thập phân của giá trị được lưu trữ ở dạng nhị phân. Nếu Python xuất giá trị thập phân thực của xấp xỉ nhị phân được lưu trữ cho 0. 1, nó sẽ xuất ra

>>> 0.1
0.1000000000000000055511151231257827021181583404541015625

Đây là số thập phân nhiều hơn so với hầu hết mọi người mong đợi, vì vậy Python hiển thị giá trị được làm tròn để cải thiện khả năng đọc

________số 8_______

Điều quan trọng là phải hiểu rằng trong thực tế đây là một ảo ảnh. giá trị được lưu trữ không chính xác 1/10, nó chỉ đơn giản là trên màn hình giá trị được lưu trữ được làm tròn. Điều này trở nên rõ ràng ngay khi bạn thực hiện các phép toán số học với các giá trị này

>>> 0.1 + 0.2
0.30000000000000004

Hành vi này là cố hữu đối với bản chất của biểu diễn dấu phẩy động của máy. nó không phải là lỗi trong Python, cũng không phải là lỗi trong mã của bạn. Bạn có thể quan sát cùng một loại hành vi trong tất cả các ngôn ngữ khác sử dụng hỗ trợ phần cứng để tính toán số dấu phẩy động (mặc dù một số ngôn ngữ không hiển thị sự khác biệt theo mặc định hoặc không hiển thị trong tất cả các chế độ hiển thị)

Một bất ngờ khác vốn có trong cái này. Ví dụ: nếu bạn cố gắng làm tròn giá trị 2. 675 đến hai chữ số thập phân, bạn sẽ nhận được

0.001
0

Tài liệu về nguyên hàm round() chỉ ra rằng nó làm tròn đến giá trị gần nhất cách xa 0. Vì phân số thập phân chính xác nằm giữa 2. 67 và 2. 68, bạn sẽ nhận được (xấp xỉ nhị phân của) 2. 68. Tuy nhiên, đây không phải là trường hợp vì khi phân số thập phân 2. 675 được chuyển đổi thành float, nó được lưu trữ bằng một giá trị gần đúng có giá trị chính xác là

0.001
1

Vì xấp xỉ gần hơn một chút với 2. 67 hơn 2. 68, làm tròn xuống

Nếu bạn đang ở trong tình huống cần làm tròn số thập phân giữa chừng, bạn nên sử dụng mô-đun thập phân. Nhân tiện, mô-đun thập phân cũng cung cấp một cách thuận tiện để "xem" giá trị chính xác được lưu trữ cho bất kỳ số float nào.

0.001
2

Một hệ quả khác của thực tế là 0. 1 không được lưu trữ chính xác trong 1/10 là tổng của mười giá trị bằng 0. 1 không cho 1. 0 một trong hai

0.001
3

Số học của các số dấu phẩy động nhị phân chứa nhiều điều bất ngờ như vậy. Vấn đề với "0. 1" được giải thích chi tiết bên dưới, trong phần "Lỗi trình bày". Xem The Perils of Floating Point để có danh sách đầy đủ hơn về những bất ngờ như vậy

Đúng là không có câu trả lời đơn giản, tuy nhiên đừng quá nghi ngờ những con số ảo trôi nổi. Lỗi, trong Python, trong các phép toán số dấu phẩy động là do phần cứng cơ bản và trên hầu hết các máy không quá 1 trên 2 ** 53 cho mỗi phép toán. Điều này là quá cần thiết đối với hầu hết các tác vụ, nhưng bạn nên nhớ rằng đây không phải là các phép toán thập phân và mọi phép toán trên các số dấu phẩy động có thể bị lỗi mới

Mặc dù vẫn tồn tại các trường hợp bệnh lý, đối với hầu hết các trường hợp sử dụng phổ biến, cuối cùng bạn sẽ nhận được kết quả như mong đợi bằng cách chỉ cần làm tròn đến số vị trí thập phân mà bạn muốn trên màn hình. Để kiểm soát tốt cách hiển thị số float, hãy xem Cú pháp định dạng chuỗi để biết thông số kỹ thuật định dạng của str. phương thức định dạng ()

Phần này của câu trả lời giải thích chi tiết ví dụ về "0. 1" và cho biết cách bạn có thể tự mình thực hiện phân tích chính xác loại trường hợp này. Chúng tôi giả định rằng bạn đã quen thuộc với biểu diễn nhị phân của các số dấu phẩy động. Thuật ngữ Lỗi biểu diễn có nghĩa là hầu hết các phân số thập phân không thể được biểu diễn chính xác ở dạng nhị phân. Đây là lý do chính tại sao Python (hoặc Perl, C, C ++, Java, Fortran và nhiều thứ khác) thường không hiển thị kết quả chính xác ở dạng thập phân

>>> 0.1 + 0.2
0.30000000000000004

Tại sao ? . Tuy nhiên, tất cả các máy ngày nay (tháng 7 năm 2010) đều tuân theo tiêu chuẩn IEEE-754 cho số học của các số dấu phẩy động. và hầu hết các nền tảng đều sử dụng "độ chính xác kép IEEE-754" để thể hiện Python nổi. Độ chính xác kép IEEE-754 sử dụng độ chính xác 53 bit, do đó, khi đọc, máy tính sẽ cố chuyển đổi 0. 1 đến phân số gần nhất có dạng J / 2 ** N với J là số nguyên chính xác 53 bit. viết lại

0.001
5

Trong

0.001
6

nhớ rằng J chính xác là 53 bit (vì vậy> = 2 ** 52 nhưng <2 ** 53), giá trị tốt nhất có thể cho N là 56

0.001
7

Vì vậy, 56 là giá trị duy nhất có thể có cho N để lại chính xác 53 bit cho J. Do đó, giá trị tốt nhất có thể cho J là thương số này, được làm tròn

0.001
8

Vì carry lớn hơn một nửa của 10, giá trị gần đúng nhất thu được bằng cách làm tròn lên

0.001
9

Do đó, xấp xỉ tốt nhất có thể cho 1/10 trong "độ chính xác kép IEEE-754" là trên 2 ** 56, nghĩa là

0.3
0

Lưu ý rằng vì việc làm tròn được thực hiện hướng lên trên nên kết quả thực sự lớn hơn 1/10 một chút; . Nhưng không có trường hợp nào là chính xác 1/10

Vì vậy, máy tính không bao giờ "thấy" 1/10. những gì nó nhìn thấy là phân số chính xác được đưa ra ở trên, giá trị gần đúng nhất bằng cách sử dụng các số dấu phẩy động có độ chính xác kép từ "" IEEE-754 "

0.3
1

Nếu chúng ta nhân phân số này với 10 ** 30, chúng ta có thể quan sát các giá trị của 30 chữ số thập phân có trọng số mạnh

0.3
2

nghĩa là giá trị chính xác được lưu trữ trong máy tính xấp xỉ bằng giá trị thập phân 0. 100000000000000005551115123125. Trong các phiên bản trước Python 2. 7 và Trăn 3. 1, Python làm tròn các giá trị này đến 17 chữ số thập phân có nghĩa, hiển thị “0. 10000000000000001”. Trong các phiên bản hiện tại của Python, giá trị được hiển thị là giá trị có phân số càng ngắn càng tốt trong khi đưa ra biểu diễn chính xác giống như vậy khi được chuyển đổi trở lại nhị phân, chỉ hiển thị “0. 1”

Tại sao 0. 1 0. 2 không bằng 0. 3 trong JS?

Tùy thuộc vào số lượng bit chính xác có sẵn , các xấp xỉ dấu phẩy động của 0. 1 và 0. 2 có thể nhỏ hơn hoặc lớn hơn một chút so với các biểu diễn thập phân tương ứng, nhưng không bao giờ bằng. Vì thực tế đó, bạn sẽ không bao giờ có 0. 1+0. 2 == 0. 3.

Tại sao 0. 1 0. 2 == 0. 3 trả về sai?

0. 1 + 0. 2. này bằng 0. 3, nhưng ở dạng dấu phẩy động. (0. 1 + 0. 2) == 0. 3 là sai. Điều này là do 0. 1, 0. 2 và 0. 3 không thể được biểu diễn chính xác trong dấu phẩy động cơ số 2 .

đầu ra của 0 là gì. 1 0. 2 trong JavaScript?

Tôi vô cùng ngạc nhiên khi biết rằng 0. 1 + 0. 2 thực sự được cho là bằng 0. 30000000000000004 trong JavaScript do phép toán dấu phẩy động.

Tại sao là 0. 1 0. 1 0. 1 == 0. 3 sai?

Biểu thức print (0. 1 + 0. 1 + 0. 1 == 0. 3) đánh giá là Sai trong Python do cách biểu diễn và lưu trữ các số dấu phẩy động trong bộ nhớ máy tính . Khi làm việc với các giá trị thập phân, máy tính phải sử dụng phép tính gần đúng, điều này có thể dẫn đến mất độ chính xác.