Tại sao máy tính không lưu số thập phân dưới dạng số thứ hai?


24

Máy tính gặp sự cố khi lưu trữ các số phân số trong đó mẫu số là một thứ khác với giải pháp cho 2 ^ x. Điều này là do chữ số đầu tiên sau số thập phân có giá trị 1/2, 1/4 thứ hai (hoặc 1 / (2 ^ 1) và 1 / (2 ^ 2)), v.v.

Tại sao phải xử lý tất cả các loại lỗi làm tròn khi máy tính có thể vừa lưu phần thập phân của số dưới dạng một số nguyên khác (do đó chính xác?)

Điều duy nhất tôi có thể nghĩ đến là xử lý các số thập phân lặp lại (trong cơ sở 10), nhưng có thể có một giải pháp cạnh cho điều đó (như chúng ta hiện đang có với vô hạn).


8
Bạn nên tìm kiếm cách lưu trữ các loại thập phân, ngược lại với các kiểu float / double.
Oded

9
Không biết làm thế nào là chính xác hơn. Chữ số đầu tiên sau số thập phân là 1/10 1/100 thứ hai, v.v ... Làm thế nào chính xác hơn mà bạn vẫn gặp các vấn đề làm tròn (làm thế nào để bạn đại diện cho 1/3)? Sự khác biệt duy nhất là giá trị nào có thể được biểu diễn chính xác.
Martin York

17
Điểm nổi thập phân (là những gì bạn đang đề cập đến hai, chỉ trong một biểu diễn khó xử hơn) không chính xác hơn điểm nổi nhị phân. Sự khác biệt duy nhất là giá trị nào không thể được biểu thị và vì chúng tôi đã sử dụng hệ thống thập phân nên chúng tôi không nhận thấy các lỗi của phiên bản thập phân. Và không, không thể đại diện cho tất cả các số hữu tỷ và không hợp lý.

1
Vào cuối ngày, nó sôi sục đến hiệu quả. Máy tính là nhị phân và các mạch để làm việc với biểu diễn nhị phân này ít phức tạp hơn nhiều. Tầm quan trọng của điều này có thể giảm đi phần nào ngày hôm nay, nhưng đó là thời điểm mà điều này rất có ý nghĩa. Ngoài ra, bất kỳ đại diện nào bạn chọn để lưu trữ số của mình (trong một không gian hữu hạn) trên máy tính sẽ có một bộ giá trị hữu hạn mà nó có thể đại diện và tất cả chúng sẽ thể hiện các lỗi làm tròn với một số đầu vào. Định dạng dấu phẩy động điển hình với Mantissa và Exponent cung cấp phạm vi lớn hơn nhiều khi có thể sử dụng hai số nguyên.
Mr.Mindor

1
Tôi đặc biệt khuyên bạn nên đọc qua một số bài viết được tham khảo trong câu trả lời của tôi cho câu hỏi Điều gì gây ra lỗi làm tròn dấu phẩy động? mà tôi vừa cập nhật với các chi tiết của bài viết cuối cùng trong loạt bài tham khảo. Cụ thể, hãy xem Tại sao Điểm cố định không chữa được Điểm nổi của bạn .
Đánh dấu gian hàng

Câu trả lời:


35

Có những chế độ thực sự của những con số làm điều đó.

Số học thập phân mã hóa nhị phân (BCD) có máy tính hoạt động ở cơ sở 10. Lý do bạn hiếm khi gặp phải điều này là lãng phí không gian: mỗi chữ số của một số mất tối thiểu bốn bit, trong khi máy tính có thể lưu trữ tối đa 16 giá trị trong không gian đó. (Nó cũng có thể chậm hơn, nhưng có thể có toán học BCD tăng tốc phần cứng hoạt động tốt.). Trên thực tế, đây chính xác là những gì hầu hết các máy tính làm, đó là lý do tại sao có một số loại vấn đề làm tròn nhất định mà bạn sẽ không bao giờ gặp phải trên chiếc Casio 5 đô la sẽ ăn bữa trưa của bạn trên máy tính để bàn.

Con đường khác bạn có thể đi là sử dụng các số hữu tỷ - nghĩa là tử số và mẫu số, được lưu dưới dạng số nguyên. Điều này thực sự có sẵn trong gần như tất cả các ngôn ngữ, chính xác và cho phép bạn lưu trữ mọi thứ ở định dạng nhị phân gốc. Vấn đề là vào cuối ngày, người dùng có thể không muốn thấy các phân số như 463/13, thậm chí 35 và 8/13. Họ muốn xem 35.615 ..., và thời điểm bạn đến đó, bạn phải đối mặt với tất cả các vấn đề điển hình. Thêm vào đó, định dạng này thậm chí còn chiếm nhiều không gian hơn và có thể chậm hơn đáng kể so với số học dấu phẩy động và bạn sẽ thấy không có máy tính nào sử dụng định dạng này theo mặc định.

Vì vậy: máy tính có thể làm những gì bạn muốn, nhưng nó chậm và lãng phí không gian, vì vậy chúng chỉ làm điều đó khi chúng thực sự phải làm. Thời gian còn lại, tốc độ và tiết kiệm không gian của điểm nổi là một sự đánh đổi tốt hơn.


Ý bạn là bốn bit (không phải byte) trong đoạn BCD?

3
Tùy chọn khác là số học điểm cố định, trong đó một số nguyên biểu thị phân số thập phân nếu một số - ví dụ: Lưu trữ giá trị tiền (không tính toán liên quan đến số thập phân hoặc tỷ lệ phần trăm) trong đó 1 đại diện cho 0,01 đô la.
mattnz

1
@mattnz: Điểm cố định thật sự là một trường hợp đặc biệt của lý trí.
Jon Purdy

Tuyệt vời, không biết rằng máy tính đã làm điều đó.
Một số chú mèo con

3
Có một lựa chọn thứ ba. Điểm nổi có số mũ thập phân, như cách decimaltriển khai C # : stackoverflow.com/a/5019178/174335 Không phải là BCD vì không có đại diện riêng cho các chữ số thập phân và không phải là điểm cố định.
Joren

38

Có rất nhiều cách để lưu trữ số phân số, và mỗi cách đều có ưu điểm và nhược điểm.

Điểm nổi là, cho đến nay, là định dạng phổ biến nhất. Nó hoạt động bằng cách mã hóa một dấu hiệu, một lớp phủ và số mũ cơ sở 2 đã ký thành các số nguyên và đóng gói chúng thành một bó bit. Ví dụ: bạn có thể có mantissa 32 bit 0.5(được mã hóa dưới dạng 0x88888888) và số mũ có chữ ký 32 bit của +3( 0x00000003), sẽ giải mã thành 4.0(0.5 * 2 ^ 3). Các số dấu phẩy động rất nhanh, vì chúng được triển khai trong phần cứng và các thang đo chính xác của chúng với kích thước tuyệt đối, nghĩa là, số càng nhỏ thì độ chính xác tuyệt đối của bạn càng tốt, do đó sai số làm tròn tương đối không đổi với kích thước tuyệt đối. Phao là tuyệt vời cho các giá trị được lấy mẫu từ một miền liên tục, chẳng hạn như độ dài, mức áp suất âm thanh, mức độ ánh sáng, v.v. và do đó, chúng thường được sử dụng trong xử lý âm thanh và hình ảnh, cũng như phân tích thống kê và mô phỏng vật lý. Nhược điểm lớn nhất của chúng là chúng không chính xác, nghĩa là chúng dễ bị lỗi làm tròn và chúng không thể biểu diễn chính xác tất cả các phân số thập phân. Tất cả các ngôn ngữ lập trình chính thống có một điểm nổi của một số loại.

Điểm cố địnhhoạt động bằng cách sử dụng các số nguyên đủ lớn và hoàn toàn dự trữ một phần bit của chúng cho phần phân số. Ví dụ, số điểm cố định 24,8 bit dự trữ 24 bit cho phần nguyên (bao gồm cả dấu) và 8 bit cho phần phân số. Dịch chuyển sang phải số đó 8 bit cho chúng ta phần nguyên. Các số điểm cố định được sử dụng phổ biến khi các đơn vị dấu phẩy động phần cứng không phổ biến hoặc ít nhất là chậm hơn nhiều so với các số nguyên của chúng. Mặc dù các số điểm cố định có phần dễ xử lý hơn về mặt chính xác (nếu chỉ vì chúng dễ lý do hơn), chúng kém hơn nhiều so với các số khác - chúng có độ chính xác thấp hơn, phạm vi nhỏ hơn và vì thêm các phép toán là cần thiết để sửa các phép tính cho sự dịch chuyển ngầm định, toán học điểm cố định ngày nay thường chậm hơn toán học dấu phẩy động.

Các loại số thập phân hoạt động giống như số float hoặc số điểm cố định, nhưng chúng giả sử một hệ thập phân, nghĩa là số mũ của chúng (ẩn hoặc rõ ràng) mã hóa lũy thừa 10, không phải lũy thừa 2. Ví dụ, một số thập phân có thể mã hóa một 23456số mũ và số mũ của -2, và điều này sẽ mở rộng thành234.56. Số thập phân, vì số học không được kết nối cứng vào CPU, chậm hơn số float, nhưng chúng lý tưởng cho mọi thứ liên quan đến số thập phân và cần chính xác các số đó, với việc làm tròn xảy ra ở các điểm được xác định rõ - tính toán tài chính, bảng điểm, v.v ... Một số ngôn ngữ lập trình có các loại thập phân được tích hợp trong đó (ví dụ C #), một số ngôn ngữ khác yêu cầu các thư viện để thực hiện chúng. Lưu ý rằng mặc dù số thập phân có thể biểu thị chính xác các phân số thập phân không lặp lại, độ chính xác của chúng không tốt hơn số thập phân; chọn số thập phân chỉ có nghĩa là bạn có được các biểu diễn chính xác của các số có thể được biểu diễn chính xác trong một hệ thập phân (giống như số float có thể biểu diễn chính xác các phân số nhị phân).

Các số hợp lý lưu trữ một tử số và một bộ khử, thường sử dụng một số loại số nguyên bignum (một loại số có thể phát triển lớn như các ràng buộc bộ nhớ của máy tính cho phép). Đây là loại dữ liệu duy nhất trong nhóm có thể mô hình chính xác các số như 1/3hoặc 3/17, cũng như các thao tác trên chúng - các số liệu hợp lý, không giống như các loại dữ liệu khác, sẽ tạo ra kết quả chính xác cho những thứ như3 * 1/3. Toán học khá đơn giản, mặc dù việc đưa ra một thuật toán bao thanh toán hiệu quả là khá khó khăn. Một số ngôn ngữ lập trình có các loại hợp lý được tích hợp vào chúng (ví dụ Common Lisp). Nhược điểm của các lý do bao gồm chúng chậm (nhiều thao tác yêu cầu giảm phân số và bao thanh toán các thành phần của chúng) và nhiều thao tác phổ biến là khó hoặc không thể thực hiện được, và hầu hết các triển khai sẽ làm giảm tỷ lệ hợp lý xuống mức nổi khi điều này xảy ra (ví dụ: khi bạn gọi sin()trên một lý trí).

BCD (Binary Coded Decimal) sử dụng "nibble" (nhóm 4 bit) để mã hóa các chữ số riêng lẻ; vì một nibble có thể chứa 16 giá trị khác nhau, nhưng các số thập phân chỉ cần 10, có 6 giá trị "bất hợp pháp" trên mỗi nibble. Giống như số thập phân, số BCD là số thập phân chính xác, nghĩa là các phép tính được thực hiện trên số thập phân hoạt động giống như khi bạn sử dụng bút và giấy. Các quy tắc số học cho BCD có phần vụng về, nhưng nhược điểm là việc chuyển đổi chúng thành chuỗi dễ dàng hơn so với một số định dạng khác, đặc biệt thú vị đối với môi trường tài nguyên thấp như hệ thống nhúng.

Các chuỗi , vâng, các chuỗi cũ đơn giản, cũng có thể được sử dụng để biểu diễn các số phân số. Về mặt kỹ thuật, điều này rất giống với BCD, chỉ có một dấu thập phân rõ ràng và bạn sử dụng một byte đầy đủ cho mỗi chữ số thập phân. Như vậy, định dạng là lãng phí (chỉ có 11 trong số 256 giá trị có thể được sử dụng), nhưng nó dễ phân tích và tạo hơn so với BCD. Ngoài ra, bởi vì tất cả các giá trị được sử dụng là "không đáng tin cậy", các số được mã hóa chuỗi trung tính, vô hại và nền tảng có thể đi qua các mạng mà không gặp sự cố. Rất hiếm khi tìm thấy số học được thực hiện trực tiếp trên các chuỗi, nhưng có thể, và khi bạn làm điều đó, chúng chỉ chính xác thập phân như các định dạng thập phân khác (số thập phân và BCD).


Chắc chắn điểm cố định 32 bit có độ chính xác cao hơn điểm nổi 32 bit, vì các biểu diễn điểm cố định không bao gồm một lớp phủ.
han

4
@han: Phụ thuộc vào kích thước của số bạn muốn lưu trữ. Phao sẽ (đại khái) cung cấp cho bạn độ chính xác như nhau cho dù số lượng lớn hay nhỏ trong khi điểm cố định sẽ chỉ cung cấp cho bạn độ chính xác đầy đủ nếu số bạn muốn lưu trữ hoàn toàn phù hợp với phạm vi của nó.
Leo

@han Không nhất thiết, cả hai vẫn có thể đại diện cho 2 ^ 32 giá trị riêng biệt. Lượng thông tin mang theo là giống hệt nhau, bất kể trình bày. Phạm vi và độ chính xác đi đôi với nhau, do đó, về mặt số học điểm cố định có thể chính xác hơn trong các phạm vi nhất định. Và tránh các vấn đề làm tròn ngẫu nhiên khó chịu, nếu bạn biết các giới hạn mà bạn có thể làm việc với.
zxcdw

@han: chúng có cùng độ chính xác (hoặc gần như). Sự khác biệt là đối với các số điểm cố định, độ chính xác (như kích thước của một bước rời rạc từ một số đến số kế tiếp của nó) là không đổi, giống như với các số nguyên, trong khi với số float, nó tăng trưởng một cách tuyến tính với giá trị tuyệt đối - số float số 1.0 có độ chính xác cao hơn số 10.000.000.0 (gấp một triệu lần, đại khái).
tdammers

6

Số dấu phẩy động đại diện cho một loạt các giá trị, rất hữu ích khi bạn không biết trước các giá trị có thể là gì, nhưng đó là một sự thỏa hiệp. Đại diện cho 1/10 ^ 100 với số nguyên thứ hai sẽ không hoạt động.

Một số ngôn ngữ (và một số thư viện) có các đặc điểm khác. Lisp theo truyền thống có số nguyên chính xác vô hạn. Cobol có các phép tính với số thập phân điểm cố định.

Bạn phải chọn đại diện số của bạn phù hợp với miền vấn đề.


1

Có vẻ như bạn đang mô tả các số điểm cố định .

Hãy nhớ rằng việc lưu trữ phần phân số của một số ở một vị trí riêng biệt hoàn toàn giống hệt với việc tạo một không gian duy nhất, dài gấp đôi và lưu trữ toàn bộ và phần phân đoạn trong hai nửa riêng biệt. Nói cách khác, nó giống hệt với việc lưu trữ số dưới dạng một số nguyên nhưng chỉ đơn giản là giả sử một số lượng không gian thập phân cố định.

Thông thường các số dấu phẩy động được lưu trữ bằng cách sử dụng một biến thể nhị phân trên ký hiệu khoa học bởi vì điều thường quan trọng là các chữ số có nghĩa. Nhiều phương pháp khác tồn tại mặc dù. Số thập phân điểm cố định thường được sử dụng ví dụ để lưu trữ giá trị tiền tệ, trong đó độ chính xác rất quan trọng cho đến một số thập phân nhất định nhưng số chữ số thập phân bắt buộc không bao giờ thay đổi.


1

Đó sẽ được gọi là BCD, tôi nghĩ bạn vẫn có thể sử dụng nó nếu bạn thực sự muốn. Tuy nhiên, nó không thực sự xứng đáng như:

  1. Bạn sẽ rất hiếm khi gặp phải lỗi làm tròn với điểm nổi 64 bit
  2. Nó làm cho phức tạp và không hiệu quả
  3. Nó lãng phí 6 giá trị cứ sau 4 bit

Toán BCD được sử dụng rất nhiều trên các hệ thống vi xử lý 8 bit đầu tiên; thật vậy, trên một bộ vi xử lý phổ biến (6502), phép cộng và phép trừ với BCD chỉ nhanh trên mỗi byte như với nhị phân. Trò chơi điện tử thường xuyên sử dụng toán học BCD để giữ điểm. Không có xử lý đặc biệt cho gói điểm ở 1.000.000 điểm. Thay vào đó, việc thêm 1 vào "99 99 99" sẽ mang lại "00 00 00" với việc mang theo bị bỏ qua. Chi phí bổ sung của việc thêm điểm tại BCD là rất nhỏ so với chi phí chuyển đổi giá trị nhị phân sang định dạng hiển thị.
supercat

1

Câu trả lời ngắn gọn là điểm nổi được thiết kế cho các tính toán khoa học. Nó có thể lưu trữ một số với (tối đa) một số chữ số có nghĩa được chỉ định, phù hợp chặt chẽ với cách đo chính xác trong hầu hết các tính toán khoa học.

Điều đó có xu hướng được hỗ trợ trong phần cứng bởi vì các tính toán khoa học có xu hướng là những người được hưởng lợi nhiều nhất từ ​​hỗ trợ phần cứng. Ví dụ, các tính toán tài chính thường được thực hiện với các định dạng khác - nhưng phần mềm tài chính thường không đủ tính toán thực tế rằng mặc dù các định dạng cần thiết chỉ được hỗ trợ trong phần mềm, hiệu suất vẫn hoàn toàn phù hợp với hầu hết các phần mềm tài chính.

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.