2012-04-28 47 views
7

Đầu tiên, đây không phải là câu hỏi về độ chính xác hoặc bất kỳ thứ gì như thế.Biểu thị số nhị phân

Câu hỏi của tôi là, trình biên dịch quyết định cách trình bày một số?

Hãy lấy C chẳng hạn. Tôi viết

double d = 4.5632; 

Làm thế nào để chọn biểu diễn nhị phân? Tôi biết nó không đại diện chính xác, vì vậy làm thế nào nó chọn số đại diện gần nhất? Nó được thực hiện tại thời gian biên dịch? Nó được thực hiện bởi CPU hay hệ điều hành?

Vui lòng chỉ trả lời nếu bạn biết điều này xảy ra như thế nào, câu trả lời như "đừng lo lắng về điều đó" không hữu ích. Ngoài ra, "nó phụ thuộc vào nền tảng" cũng không hữu ích, bạn có thể chọn một nền tảng và giải thích cho điều đó.

+3

Máy tính không "chọn" biểu diễn nhị phân - nhà thiết kế phần cứng và nhà văn biên dịch làm. Hãy xem [tiêu chuẩn này] (http://en.wikipedia.org/wiki/IEEE_754-2008). – dasblinkenlight

Trả lời

6

Trình biên dịch không quyết định (thường). CPU (thường) có một đơn vị dấu chấm động, đòi hỏi các giá trị dấu phảy động được biểu diễn theo một định dạng cụ thể (thường là IEEE-754). Tất nhiên, có thể mô phỏng một kiến ​​trúc hoàn toàn khác, trong trường hợp đó tác giả trình biên dịch/giả lập được tự do chọn một biểu diễn hoàn toàn khác. Nhưng đây không phải là điển hình.

Cách đại diện từ vựng cụ thể 4.5632 được chuyển đổi thành biểu diễn cơ bản, được chỉ định theo tiêu chuẩn C. Vì vậy, từ mục 6.4.4.2 của tiêu chuẩn C99 (tôi đã đánh dấu phần có liên quan nhất):

Phần có ý nghĩa được hiểu là (số thập phân hoặc thập lục phân) số hợp lý; trình tự chữ số trong phần số mũ là được hiểu là số nguyên thập phân. Đối với các hằng số dấu thập phân, số mũ cho biết lũy thừa của 10 phần tử có phần là được chia tỷ lệ. Đối với các hằng số thả nổi thập lục phân, số mũ cho biết số sức mạnh của 2 mà phần significand được chia tỷ lệ. Đối với hằng số thả nổi thập phân và cũng cho hằng số thập lục phân khi FLT_RADIX không phải là công suất 2, kết quả là giá trị đại diện gần nhất hoặc giá trị lớn hơn hoặc nhỏ hơn liền kề với giá trị đại diện gần nhất, được chọn theo cách thực hiện được xác định. Đối với hằng số thập lục phân thập lục phân khi FLT_RADIX là lũy thừa của 2, kết quả chính xác là được làm tròn.

Điều này sẽ được thực hiện vào thời gian biên dịch (mặc dù tiêu chuẩn không ủy quyền).

+0

Và nó phụ thuộc vào tiêu chuẩn – nullpotent

+0

Điều này không trả lời câu hỏi của tôi - làm thế nào? Làm thế nào để nó biết 3.14 là để được đại diện bởi 0100111010 .... hoặc bất cứ điều gì? – AMCoder

+0

@AMCoder: Tôi hiểu lầm câu hỏi của bạn. Xem cập nhật. –

0

Có, chuyển đổi cụ thể đó được thực hiện tại thời gian biên dịch, vì double d = 4.5632; là hằng số biên dịch. Những gì được biên dịch vào mã của bạn là biểu diễn giá trị này trong định dạng dấu chấm động được sử dụng bởi kiến ​​trúc đích. Trong trường hợp đại diện IEEE-754 32 bit, đây là 0x409205BC. Làm thế nào CPU "biết" rằng đây là một giá trị hơi gần 4.5632 phụ thuộc vào tiêu chuẩn điểm nổi chính nó. Một lần nữa, trong trường hợp của IEEE-754 32-bit, chúng ta có một bit cho dấu, tám bit cho số mũ, và 23 bit cho phần định trị.

Khi nói đến làm tròn, có một số phương pháp có thể được áp dụng. Các đặc điểm kỹ thuật IEEE-754 đề cập đến bốn phương pháp: vòng đến gần nhất, tròn đến số không, tròn đến vô cực âm, tròn đến vô cùng tích cực.

0

Trình biên dịch tạo chương trình chạy trên nền tảng. Nền tảng có thể đã tồn tại trước trình biên dịch hoặc ngược lại. Biểu diễn nhị phân của tất cả mọi thứ soạn ABI, về cơ bản là một đặc điểm kỹ thuật của đầu ra của trình biên dịch. Cuối cùng, mọi thứ được thực hiện tuy nhiên chúng được thực hiện, vì lý do gì, nhưng hy vọng có một ABI để nói chính xác những gì sẽ xảy ra. Trong thực tế, hầu như tất cả các nền tảng đều thực hiện số học dấu phẩy động theo IEEE 754, hay còn gọi là IEC 559. Tiêu chuẩn quốc tế khá cũ này xác định bit của một số dấu phẩy động và cách biểu diễn số thập phân của chương trình cho một giá trị dấu phảy động.

Nền tảng không có FPU sẽ vẫn đóng gói và giải nén bitfields từ số IEEE 754 trong phần mềm, vì chúng có thể xuất hiện dưới dạng nhị phân trong tệp.

Nền tảng có yêu cầu giới hạn về khả năng tương tác và độ chính xác số, chẳng hạn như GPU, có khả năng thư giãn chuẩn chính xác do IEEE 754 yêu cầu, nhưng phạm vi số được xác định là tốt nhất cho nhiều ứng dụng.

Tất nhiên, bạn không thể phụ thuộc vào bất cứ điều gì nếu bạn muốn tính di động cuối cùng. Nhưng đó là một cược an toàn rằng việc chuyển đổi từ thập phân sang FP nhị phân (giả sử FPU không phải là số thập phân) được thực hiện tại thời gian biên dịch.

0

Ví dụ cụ thể của bạn, có biểu diễn nhị phân được mã hóa tại thời gian biên dịch. Nó có khả năng gọi một thư viện C (atod, sscanf, etC) và bất cứ thư viện nào với cắt ngắn hoặc làm tròn là những gì sẽ xảy ra. Và các trình biên dịch "tính năng" hoặc "quy tắc" cho những gì nó không nhất thiết phải là cùng một quy tắc thời gian chạy xảy ra khi bạn làm điều tương tự. Bạn không bao giờ nên kiểm tra sự tương đương với dấu chấm động, nhưng nếu bạn lấy giá trị thời gian biên dịch và sau đó nạp chương trình một chuỗi và chuyển đổi thời gian chạy đó (giả sử bạn chuyển giá trị 4.5632 trên dòng lệnh và sử dụng một trong các cuộc gọi thư viện) bạn sẽ không nhất thiết nhận được cùng một giá trị dấu chấm động. Tôi đã thấy các trình biên dịch (gcc, vv) thực hiện một công việc thực sự xấu với hằng số thời gian biên dịch như một quy tắc, cho một số chẳng hạn như của bạn (không nhiều trong mantissa) ưu tiên của tôi về độ chính xác là:

double d; int a; 
a 45632; 
d = a; 
d/=10000; 

Và ngay cả khi nó tối ưu hóa nó có xu hướng để có được một câu trả lời tốt hơn, chính xác hơn.

Bạn chạy nguy cơ lỗi phần cứng + hệ điều hành trong quá trình chuyển đổi gấp đôi, Hauser đã đưa ra một số nhận xét về lỗi FPU có xu hướng nằm trong phần int float và float đến int. Ngay cả khi tại thời gian biên dịch tôi sẽ giả định trình biên dịch nghĩa đen sẽ làm hai int để nổi sau đó chia hơn là làm một chuỗi để nổi trực tiếp như mã của bạn đã có.

Đã một vài năm kể từ khi tôi trình bày tất cả điều này, có thể trình biên dịch đã trở nên tốt hơn (nghi ngờ). Hy vọng rằng phần cứng đã trở nên tốt hơn (có thể, nó được sử dụng để rất hiếm khi tìm thấy một fpu mà không dễ dàng để tìm lỗi).

+0

Định dạng điểm nổi IEEE 754 thường được sử dụng. Nhưng nó phụ thuộc vào phần cứng nếu có một FPU phần cứng trên hệ thống của bạn, sau đó bất cứ định dạng nào mà phần cứng sử dụng đều có khả năng biên dịch biên dịch. Nếu nó là một fpu mềm thì nó là bất cứ định dạng nào mà fpu mềm muốn. IEEE là định dạng khó hơn/chậm hơn/ít tin cậy hơn do vô số các tính năng. định dạng ti dsp là ví dụ rõ ràng hơn, nhanh hơn, đáng tin cậy hơn, nhưng không có làm tròn hoặc vô cùng hay không. –

0

Ví dụ cụ thể của bạn được chuyển đổi bởi trình biên dịch vì nó là một chữ số thập phân. Bạn muốn các chi tiết cụ thể, vì vậy hãy chọn gcc. Nó thực hiện chuyển đổi trong real.c (Tôi không biết nếu đó là phiên bản hiện tại nhưng đó là bản sao đầu tiên tôi tìm thấy thông qua Google), trong một hàm gọi là real_from_string(). Về cơ bản nó thực hiện chuyển đổi với một bộ phận dài: trong trường hợp của bạn, 45632/10000.

(Decimal để chuyển đổi dấu chấm động là khá liên quan; kiểm tra my blog nếu bạn muốn tìm hiểu thêm.)

Các vấn đề liên quan