Sự khác biệt lớn.
Như tên của nó, a double
có độ chính xác gấp 2 lần [1] . Nói chung a có 15 chữ số thập phân chính xác, trong khi có 7.float
double
float
Đây là cách tính số chữ số:
double
có 52 bit mantissa + 1 bit ẩn: log (2 53 ) log (10) = 15,95 chữ số
float
có 23 bit mantissa + 1 bit ẩn: log (2 24 ) log (10) = 7,22 chữ số
Mất chính xác này có thể dẫn đến các lỗi cắt ngắn lớn hơn được tích lũy khi thực hiện các phép tính lặp lại, ví dụ
float a = 1.f / 81;
float b = 0;
for (int i = 0; i < 729; ++ i)
b += a;
printf("%.7g\n", b); // prints 9.000023
trong khi
double a = 1.0 / 81;
double b = 0;
for (int i = 0; i < 729; ++ i)
b += a;
printf("%.15g\n", b); // prints 8.99999999999996
Ngoài ra, giá trị tối đa của float là về 3e38
, nhưng gấp đôi là về 1.7e308
, vì vậy việc sử dụng float
có thể đạt "vô cực" (tức là một số dấu phẩy động đặc biệt) dễ dàng hơn nhiều so double
với một cái gì đó đơn giản, ví dụ như tính toán giai thừa 60.
Trong quá trình thử nghiệm, có thể một vài trường hợp thử nghiệm chứa những con số khổng lồ này, điều này có thể khiến các chương trình của bạn bị lỗi nếu bạn sử dụng phao.
Tất nhiên, đôi khi, thậm chí double
không đủ chính xác, do đó đôi khi chúng ta có long double
[1] (ví dụ trên cho 9.000000000000000066 trên Mac), nhưng tất cả các loại dấu phẩy động đều bị lỗi làm tròn , vì vậy nếu độ chính xác là rất quan trọng (ví dụ: tiền xử lý) bạn nên sử dụng int
hoặc một lớp phân số.
Hơn nữa, không sử dụng +=
để tổng hợp nhiều số dấu phẩy động, vì các lỗi tích lũy nhanh chóng. Nếu bạn đang sử dụng Python, hãy sử dụng fsum
. Nếu không, hãy thử thực hiện thuật toán tổng hợp Kahan .
[1]: Tiêu chuẩn C và C ++ không chỉ định các đại diện của float
, double
và long double
. Có thể là cả ba đều được triển khai dưới dạng chính xác kép của IEEE. Tuy nhiên, đối với hầu hết kiến trúc (gcc, MSVC; x86, x64, ARM) float
là thực sự là một IEEE đơn chính xác số điểm (binary32) nổi, và double
là một đôi có độ chính xác nổi số điểm IEEE (binary64).