độ chính xác 'float' so với 'double'


155

Mật mã

float x  = 3.141592653589793238;
double z = 3.141592653589793238;
printf("x=%f\n", x);
printf("z=%f\n", z);
printf("x=%20.18f\n", x);
printf("z=%20.18f\n", z);

sẽ cung cấp cho bạn đầu ra

x=3.141593
z=3.141593
x=3.141592741012573242
z=3.141592653589793116

trong đó trên dòng thứ ba 741012573242là rác và trên dòng thứ tư 116là rác. Có phải đôi luôn có 16 con số đáng kể trong khi phao luôn có 7 con số đáng kể? Tại sao đôi không có 14 con số đáng kể?

Câu trả lời:


146

Số dấu phẩy động trong C sử dụng mã hóa IEEE 754 .

Loại mã hóa này sử dụng một dấu hiệu, một ý nghĩa và số mũ.

Do mã hóa này, nhiều số sẽ có những thay đổi nhỏ để cho phép chúng được lưu trữ.

Ngoài ra, số chữ số có nghĩa có thể thay đổi một chút vì nó là biểu diễn nhị phân, không phải là số thập phân.

Độ chính xác đơn (float) cung cấp cho bạn 23 bit có ý nghĩa, 8 bit số mũ và 1 bit dấu.

Độ chính xác kép (gấp đôi) mang lại cho bạn 52 bit có ý nghĩa, 11 bit số mũ và 1 bit dấu.


4
C99 không, trước đây nó phụ thuộc vào trình biên dịch.
Alan Geleynse

21
-1 Tuyên bố này hoàn toàn sai: "Vì mã hóa này, bạn không bao giờ có thể đảm bảo rằng bạn sẽ không có thay đổi về giá trị của mình."
R .. GitHub DỪNG GIÚP ICE

16
@Alan: C99 không yêu cầu điểm nổi của IEEE; nó chỉ đề nghị nó
R .. GitHub DỪNG GIÚP ICE

4
@Alan: R .. là chính xác; Phụ lục F (chỉ định các ràng buộc của IEEE-754) là quy phạm, nhưng chỉ có hiệu lực nếu việc triển khai được xác định __STDC_IEC_559__. Việc triển khai không xác định rằng macro là miễn phí khi không tuân thủ theo chuẩn IEEE-754.
Stephen Canon

12
@Alan: Theo IEEE 754, nó dễ dàng đảm bảo rằng không có sự thay đổi trong giá trị 0.5, 0.046875hoặc 0.376739501953125so với cơ quan đại diện thập phân của họ. (Đây là tất cả rationals diadic với fitting tử số trong mantissa và cơ sở-2 logarit của mẫu số phù hợp trong số mũ.)
R .. GitHub DỪNG GIÚP ICE

42

Có phải đôi luôn có 16 con số đáng kể trong khi phao luôn có 7 con số đáng kể?

Số nhân đôi luôn có 53 bit đáng kể và số float luôn có 24 bit đáng kể (ngoại trừ các giá trị biến dạng, vô cực và giá trị NaN, nhưng đó là các chủ đề cho một câu hỏi khác). Đây là các định dạng nhị phân và bạn chỉ có thể nói rõ ràng về độ chính xác của các biểu diễn của chúng về các chữ số nhị phân (bit).

Điều này tương tự với câu hỏi có bao nhiêu chữ số có thể được lưu trữ trong một số nguyên nhị phân: một số nguyên 32 bit không dấu có thể lưu trữ các số nguyên với tối đa 32 bit, không ánh xạ chính xác đến bất kỳ số chữ số thập phân nào: tất cả các số nguyên có tới 9 chữ số thập phân có thể được lưu trữ, nhưng rất nhiều số có 10 chữ số cũng có thể được lưu trữ.

Tại sao đôi không có 14 con số đáng kể?

Mã hóa của một nhân đôi sử dụng 64 bit (1 bit cho dấu, 11 bit cho số mũ, 52 bit có nghĩa rõ ràng và một bit ẩn), gấp đôi số bit được sử dụng để biểu thị float (32 bit).


15

float: 23 bit có ý nghĩa, 8 bit số mũ và 1 bit dấu.

nhân đôi: 52 bit có ý nghĩa, 11 bit số mũ và 1 bit dấu.


11

Nó thường dựa trên các số liệu có ý nghĩa của cả số mũ và số có nghĩa trong cơ sở 2, không phải cơ sở 10. Từ những gì tôi có thể nói trong tiêu chuẩn C99, tuy nhiên, không có độ chính xác cụ thể nào cho phao và đôi (ngoài thực tế là 1 và 1 + 1E-5/ 1 + 1E-7có thể phân biệt [ floatdouble lặp lại]). Tuy nhiên, số lượng các số liệu quan trọng được để lại cho người thực hiện (cũng như cơ sở nào họ sử dụng nội bộ, do đó, nói cách khác, việc triển khai có thể quyết định thực hiện dựa trên 18 chữ số chính xác trong cơ sở 3). [1]

Nếu bạn cần biết các giá trị này, các hằng số FLT_RADIXFLT_MANT_DIG(và DBL_MANT_DIG/ LDBL_MANT_DIG) được xác định trong float.h.

Lý do nó được gọi doublelà vì số byte được sử dụng để lưu trữ nó gấp đôi số lượng float (nhưng điều này bao gồm cả số mũ và số mũ). Tiêu chuẩn IEEE 754 (được sử dụng bởi hầu hết các trình biên dịch) phân bổ tương đối nhiều bit cho mức ý nghĩa hơn số mũ (23 đến 9 cho floatso với 52 đến 12 cho double), đó là lý do tại sao độ chính xác cao hơn gấp đôi.

1: Mục 5.2.4.2.2 ( http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf )


Typo? C89 yêu cầu một epsilon ít nhất 1E-9cho double, không phải 1E-7.
Rufflewind


4

Nó không chính xác gấp đôi vì cách thức hoạt động của IEEE 754 và bởi vì nhị phân không thực sự dịch tốt sang số thập phân. Hãy xem tiêu chuẩn nếu bạn quan tâm.


4

float là viết tắt của số dấu phẩy động. Trong C, kiểu dữ liệu float được sử dụng trong những trường hợp trong đó độ chính xác của tổng số chữ số là 7. Ví dụ: - số thập phân không. 12,3546987 không thể được lưu trữ trong float vì nó có tổng cộng 9 chữ số. Đầu ra sẽ được hiển thị là 12,354699 tức là 7 chữ số đầu tiên sẽ được hiển thị như được nhập vào đầu vào và chữ số 8 sẽ được làm tròn. Kiểu float có thể biểu thị các giá trị trong khoảng từ 1,5 x 10 ^ (- 45) đến 3,4 x 10 ^ (38). Về mặt phân bổ bộ nhớ, float là loại dữ liệu dấu phẩy động 32 bit có độ chính xác đơn.

Không giống như float, double có độ chính xác từ 15 đến 16 chữ số. Phạm vi của double là 5.0 × 10 ^ (- 345) đến 1.7 × 10 ^ (308). Về mặt phân bổ byte, double là dữ liệu dấu phẩy động 64 bit kiểu.

Vấn đề phát sinh trong use.float hoặc double của nó không ảnh hưởng đến printf nhưng trong trường hợp scanf, kiểu dữ liệu phù hợp sẽ được sử dụng tùy thuộc vào tổng số không. các chữ số trong số không trôi nổi. đó là được đọc từ đầu vào.

Do đó, gấp đôi được ưu tiên hơn float cho độ chính xác cao hơn của dữ liệu.

Hi vọng điêu nay co ich.

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.