Số nguyên "không nổi" lớn nhất có thể được lưu trữ trong loại kép IEEE 754 mà không làm mất độ chính xác là gì?
Số nguyên "không nổi" lớn nhất có thể được lưu trữ trong loại kép IEEE 754 mà không làm mất độ chính xác là gì?
Câu trả lời:
Số nguyên lớn nhất / lớn nhất có thể được lưu trữ trong một gấp đôi mà không làm mất độ chính xác giống như giá trị lớn nhất có thể có của một gấp đôi. Đó là, DBL_MAX
hoặc xấp xỉ 1,8 × 10 308 (nếu gấp đôi của bạn là gấp đôi 64-bit 64 bit). Đó là một số nguyên. Nó được đại diện chính xác. Nhiều hơn những gì bạn muốn?
Tiếp tục, hỏi tôi số nguyên lớn nhất là gì, sao cho nó và tất cả các số nguyên nhỏ hơn có thể được lưu trữ trong nhân đôi 64 bit mà không làm mất độ chính xác. Bộ đôi IEEE 64 bit có 52 bit mantissa, vì vậy tôi nghĩ đó là 2 53 :
Hoặc một cách khác để xem xét nó: một khi độ lệch đã được loại bỏ theo số mũ và bỏ qua bit dấu là không liên quan đến câu hỏi, giá trị được lưu trữ bởi một nhân đôi là lũy thừa 2, cộng với số nguyên 52 bit nhân với 2 số mũ - 52 . Vì vậy, với số mũ 52, bạn có thể lưu trữ tất cả các giá trị từ 2 52 đến 2 53 - 1. Sau đó, với số mũ 53, số tiếp theo bạn có thể lưu trữ sau 2 53 là 2 53 + 1 × 2 53 - 52 . Vì vậy, mất độ chính xác đầu tiên xảy ra với 2 53 + 1.
9007199254740992 (đó là 9,007,199,254,740,992) không có bảo đảm :)
Chương trình
#include <math.h>
#include <stdio.h>
int main(void) {
double dbl = 0; /* I started with 9007199254000000, a little less than 2^53 */
while (dbl + 1 != dbl) dbl++;
printf("%.0f\n", dbl - 1);
printf("%.0f\n", dbl);
printf("%.0f\n", dbl + 1);
return 0;
}
Kết quả
9007199254740991 9007199254740992 9007199254740992
double dbl = 1; while (dbl + 1 != dbl) dbl *= 2; while (dbl == --dbl);
sẽ cho kết quả tương tự
while (dbl == --dbl)
sẽ lặp đi lặp lại mãi mãi hay không. :) (trong trường hợp này, hoàn toàn không, vì nó là 2 ^ N). Bạn sẽ phải tiếp cận nó từ bên dưới. Nó thực sự cũng sẽ dẫn đến một ít hơn kết quả mong đợi (vì một kiểm tra trong vòng lặp while giảm dbl). Và nó phụ thuộc vào thứ tự thực hiện, nếu việc giảm được thực hiện trước hoặc sau khi đánh giá phía bên trái (không được xác định theo như tôi biết). Nếu đó là trước đây, nó sẽ luôn luôn đúng và lặp lại mãi mãi.
while (dbl + 1 != dbl) dbl++;
trong đó dbl + 1 != dbl
có thể đánh giá bằng cách sử dụng long double
toán học - xem xét FLT_EVAL_METHOD == 2
. Điều này có thể kết thúc trong một vòng lặp vô hạn.
Wikipedia có điều này để nói trong cùng bối cảnh với một liên kết đến IEEE 754 :
Trên một hệ thống máy tính thông thường, số dấu phẩy động nhị phân 'chính xác kép' (64 bit) có hệ số 53 bit (một trong số đó được ngụ ý), số mũ 11 bit và một bit dấu.
2 ^ 53 chỉ hơn 9 * 10 ^ 15.
Số nguyên lớn nhất có thể được biểu diễn trong IEEE 754 double (64 bit) giống như giá trị lớn nhất mà loại có thể biểu thị, vì giá trị đó tự nó là một số nguyên.
Điều này được thể hiện dưới dạng 0x7FEFFFFFFFFFFFFF
, được tạo thành từ:
0x7FE
(2046 đại diện cho 1023 sau khi độ lệch được trừ) thay vì 0x7FF
(2047 chỉ ra a NaN
hoặc vô cùng).0xFFFFFFFFFFFFF
là 52 bit tất cả 1.Trong hệ nhị phân, giá trị là 1 ẩn theo sau là 52 số khác từ mantissa, sau đó là 971 số không (1023 - 52 = 971) từ số mũ.
Giá trị thập phân chính xác là:
179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368
Đây là khoảng 1,8 x 10 308 .
Bạn cần nhìn vào kích thước của lớp phủ. Số điểm động 64 bit 64 bit (có 52 bit, cộng 1 ngụ ý) có thể biểu diễn chính xác các số nguyên có giá trị tuyệt đối nhỏ hơn hoặc bằng 2 ^ 53.
1.7976931348623157 × 10 ^ 308
http://en.wikipedia.org/wiki/Double_precision_floating-point_format
DECIMAL_DIG
từ <float.h>
nên đưa ra ít nhất một xấp xỉ hợp lý của điều đó. Vì liên quan đến các chữ số thập phân và nó thực sự được lưu trữ dưới dạng nhị phân, bạn có thể có thể lưu trữ một cái gì đó lớn hơn một chút mà không mất độ chính xác, nhưng chính xác thì khó nói bao nhiêu. Tôi cho rằng bạn sẽ có thể tìm ra nó từ FLT_RADIX
và DBL_MANT_DIG
, nhưng tôi không chắc là tôi hoàn toàn tin tưởng vào kết quả.
double
tương ứng trực tiếp với một loại cụ thể của IEEE, nhưng điều đó không bắt buộc và khi câu trả lời này được viết, câu hỏi cũng không đề cập đến một loại cụ thể nào.