Tại sao số thập phân không thể được biểu diễn chính xác trong nhị phân?


284

Đã có một số câu hỏi được đăng lên SO về biểu diễn dấu phẩy động. Ví dụ: số thập phân 0,1 không có biểu diễn nhị phân chính xác, vì vậy thật nguy hiểm khi sử dụng toán tử == để so sánh nó với một số dấu phẩy động khác. Tôi hiểu các nguyên tắc đằng sau biểu diễn dấu phẩy động.

Điều tôi không hiểu là tại sao, từ góc độ toán học, các số ở bên phải dấu thập phân có còn "đặc biệt" nào ở bên trái không?

Ví dụ, số 61.0 có biểu diễn nhị phân chính xác vì phần tích phân của bất kỳ số nào luôn chính xác. Nhưng con số 6.10 không chính xác. Tất cả những gì tôi đã làm là chuyển vị trí thập phân một lần và đột nhiên tôi đi từ Exactopia sang Inexactville. Về mặt toán học, không nên có sự khác biệt nội tại giữa hai số - chúng chỉ là số.

Ngược lại, nếu tôi di chuyển vị trí thập phân theo hướng khác để tạo ra số 610, thì tôi vẫn ở Exactopia. Tôi có thể tiếp tục đi theo hướng đó (6100, 610000000, 610000000000000) và chúng vẫn chính xác, chính xác, chính xác. Nhưng ngay khi số thập phân vượt qua một số ngưỡng, các con số không còn chính xác nữa.

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

Chỉnh sửa: để làm rõ, tôi muốn tránh xa cuộc thảo luận về các đại diện tiêu chuẩn ngành, chẳng hạn như IEEE, và gắn bó với những gì tôi tin là cách "thuần túy" về mặt toán học. Trong cơ sở 10, các giá trị vị trí là:

... 1000  100   10    1   1/10  1/100 ...

Trong hệ nhị phân, chúng sẽ là:

... 8    4    2    1    1/2  1/4  1/8 ...

Cũng không có giới hạn tùy ý được đặt trên những con số này. Các vị trí tăng vô thời hạn ở bên trái và bên phải.


2
Bạn có thể thấy điều này hữu ích để hiểu chính xác những gì đang diễn ra bên trong một dấu phẩy động: Giải phẫu số dấu phẩy động .
John D. Cook

57
Trong hệ nhị phân, số 3 được biểu diễn là 2¹ + 2 ° = 2 + 1. Tốt đẹp và dễ dàng. Bây giờ, hãy xem 1/3. Làm thế nào bạn đại diện cho điều đó, sử dụng quyền hạn tiêu cực của 2? Thử nghiệm một chút và bạn sẽ thấy rằng 1/3 bằng tổng của chuỗi vô hạn 2 ^ -2 + 2 ^ -4 + 2 ^ -6 + 2 ^ -8 + ..., tức là. không dễ dàng để thể hiện chính xác trong nhị phân.
Lars Haugseth

21
Jon Skeet trả lời câu hỏi trong cơ thể của bạn rất tốt. Một điều còn thiếu là bạn thực sự hỏi hai câu hỏi khác nhau. Câu hỏi tiêu đề là "tại sao các số thập phân không thể được biểu diễn chính xác trong nhị phân?" Câu trả lời là, họ có thể. Giữa tiêu đề và cơ thể của bạn, bạn đưa ra ý tưởng về "nhị phân" và ý tưởng về "biểu diễn dấu phẩy động". Dấu phẩy động là cách thể hiện số thập phân trong một số chữ số nhị phân cố định với chi phí chính xác. Nhị phân chỉ là một cơ sở khác nhau để đếm và có thể biểu thị bất kỳ số thập phân nào có thể, với số chữ số vô hạn.
Chris Blackwell

3
Có một số hệ thống có biểu diễn thập phân chính xác. Nó hoạt động khá giống như bạn mô tả. Kiểu thập phân SQL là một ví dụ. Các ngôn ngữ LISP được tích hợp sẵn. Có một số thư viện thương mại và mã nguồn mở để sử dụng các phép tính thập phân chính xác. Chỉ là không có hỗ trợ phần cứng cho việc này, và hầu hết các ngôn ngữ và phần cứng ngoài đó đều thực hiện các tiêu chuẩn của IEEE để thể hiện một số lượng vô hạn các số trong 32 hoặc 64 bit.
số

1
Câu hỏi này dường như lạc đề vì nó liên quan đến Toán học (ngay cả khi nó liên quan đến toán học lập trình) và sẽ tốt hơn về Toán học
Cole Johnson

Câu trả lời:


360

Số thập phân có thể được biểu diễn chính xác, nếu bạn có đủ không gian - chỉ không bằng số điểm nhị phân nổi . Nếu bạn sử dụng loại dấu thập phân trôi nổi (ví dụ: System.Decimaltrong .NET) thì rất nhiều giá trị không thể được biểu diễn chính xác trong dấu phẩy động nhị phân có thể được biểu diễn chính xác.

Chúng ta hãy nhìn nó theo một cách khác - trong cơ sở 10 mà bạn có thể cảm thấy thoải mái, bạn không thể diễn đạt chính xác 1/3. Đó là 0.3333333 ... (định kỳ). Lý do bạn không thể biểu thị 0,1 dưới dạng số dấu phẩy động nhị phân là vì cùng một lý do. Bạn có thể đại diện chính xác cho 3, và 9 và 27 - nhưng không phải là 1/3, 1/9 hoặc 1/27.

Vấn đề là 3 là số nguyên tố không phải là hệ số 10. Đó không phải là vấn đề khi bạn muốn nhân một số với 3: bạn luôn có thể nhân với một số nguyên mà không gặp vấn đề. Nhưng khi bạn chia cho một số nguyên tố và không phải là yếu tố cơ sở của bạn, bạn có thể gặp rắc rối (và sẽ làm như vậy nếu bạn cố chia 1 cho số đó).

Mặc dù 0,1 thường được sử dụng làm ví dụ đơn giản nhất về số thập phân chính xác không thể biểu diễn chính xác bằng dấu phẩy động nhị phân, nhưng có thể nói 0,2 là một ví dụ đơn giản hơn vì nó là 1/5 - và 5 là số nguyên tố gây ra vấn đề giữa số thập phân và nhị phân .


Lưu ý bên lề để giải quyết vấn đề đại diện hữu hạn:

Một số loại dấu thập phân trôi nổi có kích thước cố định như các System.Decimalloại khác như java.math.BigDecimal"lớn tùy ý" - nhưng chúng sẽ đạt giới hạn tại một số điểm, cho dù đó là bộ nhớ hệ thống hay kích thước tối đa theo lý thuyết của một mảng. Tuy nhiên, đây là một điểm hoàn toàn riêng biệt với câu trả lời chính của câu trả lời này. Ngay cả khi bạn có số lượng bit thực sự lớn tùy ý để chơi, bạn vẫn không thể biểu diễn chính xác số thập phân 0,1 trong biểu diễn điểm nhị phân nổi. So sánh với vòng khác: được cung cấp một số chữ số thập phân tùy ý, bạn có thể biểu diễn chính xác bất kỳ số nào có thể biểu diễn chính xác như một điểm nhị phân nổi.


8
Đó là một ví dụ tốt chết tiệt thưa ngài!
Tom Ritter

5
... Ước gì tôi có thể nâng cấp điều này hai lần. Tôi đã được hỏi về điều này hoàn toàn quá nhiều lần. Nó gần giống như mọi người không thể nghĩ ra bên ngoài căn cứ 10. hehe
Justin Niessner

38
Vâng, có 10 loại người trên thế giới - những người hiểu nhị phân và những người không.
duffymo

83
@JonSkeet: Ctrl + Alt + Delete sẽ trông khó xử chỉ bằng hai ngón tay.
Lars Haugseth

20
@muusbolla: Không. Các số được biểu thị bằng biểu diễn thập phân 1và biểu diễn thập phân 0.9...(lặp lại vô hạn 9s sau dấu thập phân) bằng nhau. Có lẽ cách dễ nhất để thấy điều này là như sau: Đặt x = 0.9.... Lưu ý rằng 10x = 9.9..... Vì vậy, 9x = 10x - x = 9.9... - 0.9... = 9do đó 9x = 9x = 1. Có nhiều cách khác để thấy điều này, nhưng tôi tin rằng đây là cách đơn giản nhất.
jason

25

Ví dụ, số 61.0 có biểu diễn nhị phân chính xác vì phần tích phân của bất kỳ số nào luôn chính xác. Nhưng con số 6.10 không chính xác. Tất cả những gì tôi đã làm là chuyển một vị trí thập phân và đột nhiên tôi đi từ Exactopia đến Inexactville. Về mặt toán học, không nên có sự khác biệt nội tại giữa hai số - chúng chỉ là số .

Chúng ta hãy rời khỏi một lúc từ các chi tiết của cơ sở 10 và 2. Hãy hỏi - về cơ bản b, những con số nào đã chấm dứt các đại diện, và những con số nào không? Suy nghĩ của một khoảnh khắc cho chúng ta biết rằng một số xcó biểu thức kết thúc bkhi và chỉ khi tồn tại một số nguyên nnhư vậy x b^nlà một số nguyên.

Vì vậy, ví dụ, x = 11/500có một đại diện 10 chấm dứt, bởi vì chúng ta có thể chọn n = 3và sau đó x b^n = 22, một số nguyên. Tuy nhiên x = 1/3, không, bởi vì bất cứ điều gì nchúng tôi chọn, chúng tôi sẽ không thể thoát khỏi 3.

Ví dụ thứ hai này nhắc chúng ta suy nghĩ về các yếu tố và chúng ta có thể thấy rằng đối với bất kỳ tỷ lệ hợp lý nào x = p/q(giả sử là ở mức thấp nhất), chúng ta có thể trả lời câu hỏi bằng cách so sánh các yếu tố chính của bq. Nếu qcó bất kỳ yếu tố chính nào không nằm trong yếu tố chính b, chúng ta sẽ không bao giờ có thể tìm thấy một nyếu tố phù hợp để loại bỏ các yếu tố này.

Do đó, đối với cơ sở 10, bất kỳ p/q nơi nàoq có các thừa số nguyên tố khác 2 hoặc 5 sẽ không có biểu diễn kết thúc.

Vì vậy, bây giờ quay trở lại cơ sở 10 và 2, chúng ta thấy rằng bất kỳ tỷ lệ hợp lý nào với biểu diễn 10 chấm dứt sẽ có dạng p/qchính xác khi qchỉ có 2s và 5s trong hệ số nguyên tố của nó; và cùng một số đó sẽ có kết thúc 2 biểu diễn chính xác khi qchỉ có 2s trong hệ số nguyên tố của nó.

Nhưng một trong những trường hợp này là một tập hợp con khác! Bất cứ khi nào

qchỉ có 2s trong hệ số nguyên tố của nó

rõ ràng cũng đúng

qchỉ có 2s và 5s trong hệ số nguyên tố của nó

hoặc, đặt một cách khác, bất cứ khi nào p/qcó một đại diện 2 chấm dứt, p/qcó một đại diện 10 chấm dứt . Tuy nhiên, converse không giữ được - bất cứ khi nào qcó 5 trong hệ số nguyên tố của nó, nó sẽ có một đại diện 10 chấm dứt, nhưng không phải là một đại diện 2 kết thúc. Đây là 0.1ví dụ được đề cập bởi các câu trả lời khác.

Vì vậy, chúng tôi có câu trả lời cho câu hỏi của bạn - bởi vì các thừa số nguyên tố 2 là tập hợp con của các thừa số nguyên tố 10, tất cả các số kết thúc 2 là số 10 chấm dứt, nhưng không phải ngược lại. Đó không phải là khoảng 61 so với 6.1 - đó là khoảng 10 so với 2.

Như một lưu ý cuối cùng, nếu bởi một số người hay sử dụng cơ sở 17, nhưng máy tính của chúng tôi đã sử dụng cơ sở 5, thì trực giác của bạn sẽ không bao giờ bị lạc hướng bởi điều này - sẽ không có số (không khác, không nguyên) chấm dứt trong cả hai trường hợp!


Vậy thì tại sao "cảnh báo (0,15 * 0,15)" hiển thị "0,0225"?
Michael Geiser

5
@MichaelGeiser câu trả lời ngắn: làm tròn tại điểm hiển thị. Những gì bạn nghĩ là 0.15thực sự (khi được lưu trữ dưới dạng gấp đôi của IEEE) `0.149999999999999994448884876874`. Xem jsfiddle .
AakashM

Đẹp rõ ràng trên ví dụ mã điểm! Tôi ước tôi có thể cho bạn một phiếu bầu cho điều đó! Tôi phải chơi với một vài chức năng để khám phá nơi xảy ra cắt vòng. Tôi vẫn còn ngạc nhiên rằng chúng ta thực sự phải xử lý rác này; vì mọi người làm việc trong cơ sở mười gần như 100% thời gian và chúng tôi sử dụng các số nguyên không nhiều thời gian đến mức bạn nghĩ rằng việc thực hiện mặc định của toán học dấu phẩy động sẽ xử lý điều vô nghĩa này.
Michael Geiser

1
@MichaelGeiser các mạch hoạt động với cơ sở 2 nhỏ hơn, nhanh hơn và tiết kiệm điện hơn so với các mạch hoạt động với cơ sở 10. Ngày nay chúng ta có thể biện minh cho chi phí hoạt động nhưng vào những năm 1970 khi các tiêu chuẩn được đặt ra, đó là một vấn đề lớn Cố gắng làm điều đó mà không có sự hỗ trợ trực tiếp của mạch xử lý thậm chí còn tồi tệ hơn, mong đợi các đơn đặt hàng có sự khác biệt lớn về tốc độ.
Đánh dấu tiền chuộc

Câu trả lời này giải thích tốt hơn chính Jon Skeet!
goelakash

16

Lý do gốc (toán học) là khi bạn đang làm việc với các số nguyên, chúng là vô hạn .

Điều đó có nghĩa là, mặc dù có một lượng vô hạn trong số chúng, chúng ta có thể "tính ra" tất cả các mục trong chuỗi, mà không bỏ qua bất kỳ mục nào. Điều đó có nghĩa là nếu chúng ta muốn có được mục ở 610000000000000vị trí thứ trong danh sách, chúng ta có thể tìm ra nó thông qua một công thức.

Tuy nhiên, con số thực là vô hạn . Bạn không thể nói "cho tôi số thực tại vị trí 610000000000000" và nhận lại câu trả lời. Lý do là bởi vì, ngay cả giữa 01, có vô số giá trị, khi bạn đang xem xét các giá trị dấu phẩy động. Điều tương tự cũng đúng với bất kỳ hai số dấu phẩy động.

Thêm thông tin:

http://en.wikipedia.org/wiki/Countable_set

http://en.wikipedia.org/wiki/Uncountable_set

Cập nhật: Tôi xin lỗi, tôi dường như đã giải thích sai câu hỏi. Câu trả lời của tôi là về lý do tại sao chúng ta không thể đại diện cho mọi giá trị thực , tôi đã không nhận ra rằng dấu phẩy động được tự động phân loại là hợp lý.


6
Trên thực tế, số hữu tỷ vô hạn. Nhưng không phải mọi số thực là một số hữu tỷ. Tôi chắc chắn có thể tạo ra một chuỗi các số thập phân chính xác sẽ đạt được bất kỳ số thập phân chính xác nào bạn muốn đưa cho tôi cuối cùng. Đó là nếu bạn cần phải đối phó với các số tỷ cũng như bạn có được vào các tập hợp vô hạn.
Jon Skeet

Đúng, tôi nên nói "thực", không phải "dấu phẩy động". Sẽ làm rõ.
TM.

1
Tại thời điểm đó logic trở nên ít áp dụng hơn, IMO - bởi vì chúng ta không chỉ không thể xử lý tất cả các số thực bằng cách sử dụng dấu phẩy động nhị phân, mà chúng ta thậm chí không thể xử tất cả các số hữu tỷ (chẳng hạn như 0,1). Nói cách khác, tôi không nghĩ nó thực sự có liên quan đến khả năng đếm được :)
Jon Skeet

@jonskeet Tôi biết rằng việc không đồng ý với Jon Skeet sẽ phá vỡ một quy luật cơ bản của tự nhiên, vì vậy tất nhiên tôi sẽ không làm điều đó :) Tuy nhiên, tôi nghĩ rằng việc thể hiện nội bộ của các con số là chỉ số cho một thiết lập các giá trị mà bạn muốn thể hiện ra bên ngoài. Với dòng suy nghĩ này, bạn có thể thấy rằng cho dù danh sách các chỉ số của bạn lớn đến mức nào (ngay cả khi bạn đã nói, các bit chính xác vô hạn), bạn vẫn không thể đại diện cho tất cả các số thực.
TM.

3
@TM: Nhưng OP không cố gắng đại diện cho tất cả các số thực. Anh ta đang cố gắng biểu diễn tất cả các số thập phân chính xác , là một tập hợp con của các số hữu tỷ, và do đó chỉ là vô hạn. Nếu anh ta đang sử dụng một tập hợp các bit vô hạn như một loại dấu phẩy động thập phân thì anh ta sẽ ổn. Việc sử dụng các bit đó làm loại dấu phẩy động nhị phân gây ra vấn đề với số thập phân.
Jon Skeet

10

Để nhắc lại những gì tôi đã nói trong nhận xét của mình với ông Skeet: chúng ta có thể đại diện cho 1/3, 1/9, 1/27 hoặc bất kỳ tỷ lệ hợp lý nào trong ký hiệu thập phân. Chúng tôi làm điều đó bằng cách thêm một biểu tượng phụ. Ví dụ: một dòng trên các chữ số lặp lại trong phần mở rộng thập phân của số. Những gì chúng ta cần để biểu diễn các số thập phân là một chuỗi các số nhị phân là 1) một chuỗi các số nhị phân, 2) một điểm cơ số và 3) một số ký hiệu khác để chỉ ra phần lặp lại của chuỗi.

Ký hiệu trích dẫn của Hehner là một cách để làm điều này. Ông sử dụng một biểu tượng trích dẫn để đại diện cho phần lặp lại của chuỗi. Bài viết: http://www.cs.toronto.edu/~hehner/ratno.pdf và mục Wikipedia: http://en.wikipedia.org/wiki/Quote_notation .

Không có gì nói rằng chúng tôi không thể thêm một biểu tượng vào hệ thống đại diện của mình, vì vậy chúng tôi có thể biểu diễn chính xác các số thập phân bằng cách sử dụng ký hiệu trích dẫn nhị phân và ngược lại.


Hệ thống ký hiệu đó hoạt động nếu chúng ta biết chu kỳ bắt đầu và kết thúc. Con người khá giỏi trong việc phát hiện chu kỳ. Nhưng, nói chung, máy tính không. Để sử dụng có thể sử dụng biểu tượng lặp lại một cách hiệu quả, máy tính sẽ phải có khả năng tìm ra vị trí của các chu kỳ sau khi thực hiện phép tính. Ví dụ, đối với số 1/3, chu kỳ bắt đầu ngay lập tức. Nhưng đối với số 1/97, chu trình không hiển thị cho đến khi bạn tìm ra câu trả lời cho ít nhất 96 chữ số. (Trên thực tế, bạn cần chắc chắn 96 * 2 + 1 = 193 chữ số.)
Barry Brown

4
Trên thực tế không khó để máy tính phát hiện chu kỳ. Nếu bạn đọc bài viết của Hehner, anh ấy mô tả cách phát hiện các chu kỳ cho các hoạt động số học khác nhau. Ví dụ, trong thuật toán chia, sử dụng phép trừ lặp đi lặp lại, bạn biết chu kỳ bắt đầu từ đâu khi bạn thấy một sự khác biệt mà bạn đã thấy trước đó.
ntownsend

3
Ngoài ra, câu hỏi là về đại diện chính xác số. Đôi khi đại diện chính xác có nghĩa là rất nhiều bit. Vẻ đẹp của ký hiệu trích dẫn là Hehner chứng minh rằng trung bình có tiết kiệm 31% về kích thước biểu diễn so với biểu diễn có độ dài cố định 32 bit tiêu chuẩn.
ntownsend

6

BCD - Số thập phân được mã hóa nhị phân - chính xác. Chúng không phải là rất hiệu quả về không gian, nhưng đó là một sự đánh đổi mà bạn phải thực hiện cho chính xác trong trường hợp này.


1
BCD không nhiều hơn hoặc ít chính xác hơn bất kỳ cơ sở nào khác. Ví dụ: làm thế nào để bạn đại diện chính xác 1/3 trong BCD? Bạn không thể.
Jörg W Mittag

12
BCD là một đại diện chính xác của một DECIMAL, do đó, phần "thập phân" của tên của nó. Không có đại diện thập phân chính xác của 1/3.
Alan

4

Đó là cùng một lý do bạn không thể đại diện chính xác 1/3 trong cơ sở 10, bạn cần nói 0.33333 (3). Trong nhị phân, đây là loại vấn đề giống nhau nhưng chỉ xảy ra đối với các bộ số khác nhau.


4

(Lưu ý: Tôi sẽ nối 'b' để chỉ ra số nhị phân ở đây. Tất cả các số khác được đưa ra dưới dạng thập phân)

Một cách để suy nghĩ về mọi thứ là về một cái gì đó như ký hiệu khoa học. Chúng ta thường thấy những con số được biểu thị bằng ký hiệu khoa học như, 6.022141 * 10 ^ 23. Số dấu phẩy động được lưu trữ bên trong bằng cách sử dụng một định dạng tương tự - mantissa và số mũ, nhưng sử dụng lũy ​​thừa của hai thay vì mười.

61.0 của bạn có thể được viết lại thành 1.90625 * 2 ^ 5 hoặc 1.11101b * 2 ^ 101b với mantissa và số mũ. Để nhân số đó với mười và (di chuyển dấu thập phân), chúng ta có thể làm:

(1.90625 * 2 ^ 5) * (1.25 * 2 ^ 3) = (2.3828125 * 2 ^ 8) = (1.19140625 * 2 ^ 9)

hoặc với mantissa và số mũ trong nhị phân:

(1.11101b * 2 ^ 101b) * (1.01b * 2 ^ 11b) = (10.0110001b * 2 ^ 1000b) = (1.00110001b * 2 ^ 1001b)

Lưu ý những gì chúng tôi đã làm ở đó để nhân số. Chúng tôi nhân số bọ ngựa và thêm số mũ. Sau đó, vì lớp phủ kết thúc lớn hơn hai, chúng tôi đã bình thường hóa kết quả bằng cách trả số mũ. Nó giống như khi chúng ta điều chỉnh số mũ sau khi thực hiện một thao tác trên các số theo ký hiệu khoa học thập phân. Trong mỗi trường hợp, các giá trị mà chúng tôi đã làm việc có biểu diễn hữu hạn ở dạng nhị phân và do đó, các giá trị đầu ra bằng phép nhân và phép cộng bổ sung cơ bản cũng tạo ra các giá trị có biểu diễn hữu hạn.

Bây giờ, hãy xem xét cách chúng tôi chia 61 cho 10. Chúng tôi sẽ bắt đầu bằng cách chia bọ ngựa, 1.90625 và 1.25. Trong số thập phân, số này cho 1.525, một số ngắn đẹp. Nhưng đây là gì nếu chúng ta chuyển đổi nó thành nhị phân? Chúng tôi sẽ làm theo cách thông thường - trừ đi sức mạnh lớn nhất của hai bất cứ khi nào có thể, giống như chuyển đổi số thập phân nguyên sang nhị phân, nhưng chúng tôi sẽ sử dụng lũy ​​thừa âm của hai:

1,525 - 1 * 2 ^ 0 -> 1
0,525 - 1 * 2 ^ -1 -> 1
0,025 - 0 * 2 ^ -2 -> 0
0,025 - 0 * 2 ^ -3 -> 0
0,025 - 0 * 2 ^ -4 -> 0
0,025 - 0 * 2 ^ -5 -> 0
0,025 - 1 * 2 ^ -6 -> 1
0,009375 - 1 * 2 ^ -7 -> 1
0,0015625 - 0 * 2 ^ -8 -> 0
0,0015625 - 0 * 2 ^ -9 -> 0
0,0015625 - 1 * 2 ^ -10 -> 1
0,0005859375 - 1 * 2 ^ -11 -> 1
0,00009765625 ...

À ồ. Bây giờ chúng tôi đang gặp rắc rối. Hóa ra 1.90625 / 1.25 = 1.525, là phân số lặp lại khi được biểu thị dưới dạng nhị phân: 1.11101b / 1.01b = 1.10000110011 ... b Máy của chúng tôi chỉ có rất nhiều bit để giữ mantissa và vì vậy chúng sẽ chỉ làm tròn phân số và giả sử số không vượt quá một điểm nhất định. Lỗi bạn thấy khi bạn chia 61 cho 10 là sự khác biệt giữa:

1.100001100110011001100110011001100110011 ... b * 2 ^ 10b
và, giả sử:
1.100001100110011001100110b * 2 ^ 10b

Chính việc làm tròn lớp phủ này dẫn đến mất độ chính xác mà chúng ta liên kết với các giá trị dấu phẩy động. Ngay cả khi mantissa có thể được thể hiện chính xác (ví dụ: khi chỉ thêm hai số), chúng ta vẫn có thể bị mất số nếu mantissa cần quá nhiều chữ số để khớp sau khi bình thường hóa số mũ.

Chúng tôi thực sự làm điều này mọi lúc khi chúng ta làm tròn số thập phân đến kích thước có thể quản lý và chỉ đưa ra một vài chữ số đầu tiên của nó. Bởi vì chúng tôi biểu thị kết quả bằng số thập phân, nó cảm thấy tự nhiên. Nhưng nếu chúng ta làm tròn một số thập phân và sau đó chuyển đổi nó sang một cơ sở khác, nó sẽ trông xấu xí như số thập phân chúng ta nhận được do làm tròn điểm nổi.


4

Đây là một câu hỏi hay.

Tất cả câu hỏi của bạn dựa trên "làm thế nào để chúng tôi đại diện cho một số?"

TẤT CẢ các số có thể được biểu diễn bằng biểu diễn thập phân hoặc biểu diễn nhị phân (phần bù 2). Tất cả bọn họ !!

NHƯNG một số (hầu hết trong số họ) yêu cầu số lượng phần tử vô hạn ("0" hoặc "1" cho vị trí nhị phân hoặc "0", "1" đến "9" cho biểu diễn thập phân).

Giống như 1/3 trong biểu diễn thập phân (1/3 = 0.3333333 ... <- với số lượng vô hạn là "3")

Giống như 0,1 trong nhị phân (0,1 = 0,00011001100110011 .... <- với số lượng vô hạn là "0011")

Tất cả mọi thứ là trong khái niệm đó. Vì máy tính của bạn chỉ có thể xem xét bộ chữ số hữu hạn (thập phân hoặc nhị phân), chỉ một số số có thể được biểu diễn chính xác trong máy tính của bạn ...

Và như Jon đã nói, 3 là số nguyên tố không phải là hệ số 10, vì vậy 1/3 không thể được biểu diễn bằng số phần tử hữu hạn trong cơ sở 10.

Ngay cả với số học với độ chính xác tùy ý, hệ thống vị trí đánh số trong cơ sở 2 không thể mô tả đầy đủ 6.1, mặc dù nó có thể đại diện cho 61.

Đối với 6.1, chúng ta phải sử dụng một biểu diễn khác (như biểu diễn thập phân hoặc IEEE 854 cho phép cơ sở 2 hoặc cơ sở 10 để biểu diễn các giá trị dấu phẩy động)


Bạn có thể đại diện cho 1/3 như chính phân số. Bạn không cần một lượng bit vô hạn để thể hiện nó. Bạn chỉ biểu diễn nó dưới dạng phân số 1/3, thay vì kết quả lấy 1 và chia cho 3. Một số hệ thống hoạt động theo cách đó. Sau đó, bạn cần một cách để sử dụng các toán tử tiêu chuẩn / * + - và tương tự để làm việc biểu diễn các phân số, nhưng điều đó khá dễ dàng - bạn có thể thực hiện các thao tác đó bằng bút và giấy, dạy máy tính thực hiện nó không phải là vấn đề lớn .
số

Tôi đã nói về "đại diện nhị phân (bổ sung 2)". Bởi vì, tất nhiên, sử dụng một đại diện khác có thể giúp bạn biểu diễn một số số có số phần tử hữu hạn (và bạn sẽ cần số lượng phần tử vô hạn cho một số phần tử khác)
ThibThib

3

Nếu bạn tạo một số đủ lớn với dấu phẩy động (vì nó có thể làm số mũ), thì bạn cũng sẽ bị thiếu chính xác trước dấu thập phân. Vì vậy, tôi không nghĩ rằng câu hỏi của bạn là hoàn toàn hợp lệ vì tiền đề là sai; không phải là trường hợp dịch chuyển 10 sẽ luôn tạo ra độ chính xác cao hơn, bởi vì tại một số điểm, số dấu phẩy động sẽ phải sử dụng số mũ để biểu thị độ lớn của số và cũng sẽ mất một số độ chính xác theo cách đó.


3

Tôi ngạc nhiên không ai tuyên bố điều này: sử dụng phân số tiếp tục . Bất kỳ số hữu tỷ có thể được biểu diễn hữu hạn trong nhị phân theo cách này.

Vài ví dụ:

1/3 (0,3333 ...)

0; 3

5/9 (0,5555 ...)

0; 1, 1, 4

10/43 (0.232558139534883720930 ...)

0; 4, 3, 3

9093/18478 (0,49209871198181621387596060179673 ...)

0; 2, 31, 7, 8, 5

Từ đây, có nhiều cách đã biết để lưu trữ một chuỗi các số nguyên trong bộ nhớ.

Ngoài việc lưu trữ số của bạn với độ chính xác hoàn hảo, các phân số tiếp tục còn có một số lợi ích khác, chẳng hạn như xấp xỉ hợp lý tốt nhất. Nếu bạn quyết định chấm dứt chuỗi số trong một phân số tiếp tục sớm, các chữ số còn lại (khi được kết hợp lại thành một phân số) sẽ cung cấp cho bạn phân số tốt nhất có thể. Đây là cách xấp xỉ với pi được tìm thấy:

Phần tiếp tục của Pi:

3; 7, 15, 1, 292 ...

Kết thúc chuỗi ở 1, điều này cho phân số:

355/113

đó là một xấp xỉ hợp lý tuyệt vời.


Nhưng làm thế nào bạn đại diện cho điều đó trong nhị phân? Ví dụ 15 yêu cầu 4 bit được biểu diễn nhưng 292 yêu cầu 9. Làm thế nào để phần cứng (hoặc thậm chí phần mềm) biết ranh giới bit nằm giữa mỗi bit? Đó là hiệu quả so với sự đánh đổi chính xác.
hăng hái

2

Trong phương trình

2^x = y ;  
x = log(y) / log(2)

Do đó, tôi chỉ tự hỏi liệu chúng ta có thể có một hệ thống cơ sở logarit cho nhị phân như,

 2^1, 2^0, 2^(log(1/2) / log(2)), 2^(log(1/4) / log(2)), 2^(log(1/8) / log(2)),2^(log(1/16) / log(2)) ........

Điều đó có thể giải quyết được vấn đề, vì vậy nếu bạn muốn viết một cái gì đó như 32,41 ở dạng nhị phân, thì đó sẽ là

2^5 + 2^(log(0.4) / log(2)) + 2^(log(0.01) / log(2))

Hoặc là

2^5 + 2^(log(0.41) / log(2))

1

Vấn đề là bạn không thực sự biết liệu con số có thực sự chính xác là 61.0 hay không. Xem xét điều này:


float a = 60;
float b = 0.1;
float c = a + b * 10;

Giá trị của c là gì? Nó không chính xác là 61, vì b không thực sự .1 vì .1 không có biểu diễn nhị phân chính xác.


1

Có một ngưỡng vì ý nghĩa của chữ số đã chuyển từ số nguyên sang số nguyên. Để đại diện cho 61, bạn có 6 * 10 ^ 1 + 1 * 10 ^ 0; 10 ^ 1 và 10 ^ 0 đều là số nguyên. 6.1 là 6 * 10 ^ 0 + 1 * 10 ^ -1, nhưng 10 ^ -1 là 1/10, đây chắc chắn không phải là số nguyên. Đó là cách bạn kết thúc ở Inexactville.


1

Một song song có thể được thực hiện các phân số và số nguyên. Một số phân số, ví dụ 1/7 không thể được biểu diễn dưới dạng thập phân mà không có rất nhiều số thập phân. Bởi vì dấu phẩy động là nhị phân dựa trên các trường hợp đặc biệt thay đổi nhưng cùng một loại vấn đề chính xác xuất hiện.


0

Có một số lượng vô hạn các số hữu tỷ và một số hữu hạn các bit để biểu diễn chúng. Xem http://en.wikipedia.org/wiki/Floating_point#Accuracy_probols .


Nhưng ngay cả với số bit vô hạn, nếu bạn đã sử dụng điểm nhị phân nổi , bạn vẫn không thể biểu diễn chính xác 0,1, giống như bạn không thể biểu thị chính xác 1/3 số thập phân ngay cả với số bit vô hạn.
Jon Skeet

3
@Jon Điều đó không đúng: với số lượng thập phân vô hạn , ví dụ tôi có thể thể hiện chính xác 'một phần ba' . Vấn đề trong thế giới thực là không thể có "số lượng vô hạn" số thập phân hoặc bit.
ChrisW

0

Số 61.0 thực sự có một hoạt động điểm nổi chính xác, nhưng điều đó không đúng với tất cả các số nguyên. Nếu bạn đã viết một vòng lặp thêm một số vào cả số dấu phẩy động có độ chính xác kép và số nguyên 64 bit, cuối cùng bạn sẽ đạt đến điểm mà số nguyên 64 bit thể hiện hoàn hảo một số, nhưng điểm nổi không ẩn bởi vì không có đủ bit đáng kể.

Nó dễ dàng hơn nhiều để đạt đến điểm gần đúng ở phía bên phải của dấu thập phân. Nếu bạn bắt đầu viết ra tất cả các số trong dấu phẩy động nhị phân, nó sẽ có ý nghĩa hơn.

Một cách nghĩ khác là khi bạn lưu ý rằng 61.0 hoàn toàn có thể biểu thị trong cơ sở 10 và thay đổi dấu thập phân xung quanh không thay đổi điều đó, bạn đang thực hiện phép nhân với lũy thừa mười (10 ^ 1, 10 ^ -1 ). Trong dấu phẩy động, nhân với lũy thừa của hai không ảnh hưởng đến độ chính xác của số. Hãy thử lấy 61.0 và chia cho ba lần liên tục để minh họa làm thế nào một con số hoàn toàn chính xác có thể mất biểu diễn chính xác của nó.


0

bạn biết số nguyên đúng không? mỗi bit đại diện cho 2 ^ n


2 ^ 4 = 16
2 ^ 3 = 8
2 ^ 2 = 4
2 ^ 1 = 2
2 ^ 0 = 1

cũng giống như điểm nổi (với một số điểm khác biệt) nhưng các bit đại diện cho 2 ^ -n 2 ^ -1 = 1/2 = 0,5
2 ^ -2 = 1 / (2 * 2) = 0,25
2 ^ -3 = 0,125
2 ^ -4 = 0,0625

Biểu diễn nhị phân dấu phẩy động:

ký Phân số mũ (tôi nghĩ vô hình 1 được gắn vào phân số)
B11 B10 B9 B8 B7 B6 B5 B4 B3 B2 B1 B0


0

Các câu trả lời điểm cao ở trên đóng đinh nó.

Đầu tiên bạn trộn cơ sở 2 và cơ sở 10 trong câu hỏi của bạn, sau đó khi bạn đặt một số ở phía bên phải không chia hết cho cơ sở, bạn sẽ gặp vấn đề. Giống như 1/3 trong số thập phân vì 3 không đi vào lũy thừa 10 hoặc 1/5 ở dạng nhị phân, không đi vào lũy thừa 2.

Một nhận xét khác mặc dù KHÔNG BAO GIỜ sử dụng bằng số dấu phẩy động, dấu chấm. Ngay cả khi nó là một đại diện chính xác, có một số con số trong một số hệ thống dấu phẩy động có thể được biểu diễn chính xác theo nhiều cách (IEEE rất tệ về điều này, đó là một thông số dấu phẩy động khủng khiếp để bắt đầu, vì vậy hãy đau đầu). Không khác nhau ở đây 1/3 không phải là THIẾT BỊ cho số trên máy tính của bạn 0.3333333, bất kể có bao nhiêu số 3 ở bên phải dấu thập phân. Nó là hoặc có thể đủ gần nhưng không bằng nhau. vì vậy bạn sẽ mong đợi một cái gì đó như 2 * 1/3 không bằng 2/3 tùy thuộc vào cách làm tròn. Không bao giờ sử dụng bằng với điểm nổi.


0

Như chúng ta đã thảo luận, trong số học dấu phẩy động, số thập phân 0,1 không thể được biểu diễn hoàn hảo trong hệ nhị phân.

Biểu diễn dấu phẩy động và số nguyên cung cấp lưới hoặc lưới cho các số được biểu diễn. Khi số học được thực hiện, các kết quả rơi ra khỏi lưới và phải được đưa trở lại vào lưới bằng cách làm tròn. Ví dụ là 1/10 trên lưới nhị phân.

Nếu chúng ta sử dụng biểu diễn thập phân được mã hóa nhị phân như một quý ông đề xuất, liệu chúng ta có thể giữ số trên lưới không?


1
Số thập phân, chắc chắn. Nhưng đó chỉ là định nghĩa. Bạn không thể đại diện cho 1/3 trong số thập phân, nhiều hơn số bạn có thể đại diện cho 0,1 ở dạng nhị phân. Bất kỳ sơ đồ lượng tử hóa đều thất bại đối với một tập hợp số lớn vô hạn.
Kylotan
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.