Trình hiển thị nổi IEEE-754
Xem chính xác cách một số thập phân được lưu trữ dưới dạng float IEEE-754 — bit dấu, bit số mũ và bit mantissa — và tại sao các số như 0,1 không được lưu trữ chính xác.
kết quả
Mỗi số dấu phẩy động mà máy tính lưu trữ - số JavaScript, số float C, số float Python - được mã hóa theo cùng một cách trong IEEE 754: một bit dấu, một khối bit số mũ và một khối bit mantissa (phân số). Độ chính xác đơn (32-bit) sử dụng 1 bit dấu, 8 bit số mũ và 23 bit định trị; độ chính xác kép (64-bit), định dạng đằng sau loại số mặc định của hầu hết mọi ngôn ngữ, sử dụng 1 bit dấu, 11 bit số mũ và 52 bit định trị. Công cụ này lấy bất kỳ số thập phân nào bạn nhập, mã hóa nó theo chiều rộng bằng cách sử dụng bộ mã hóa float DataView/ArrayBuffer của chính trình duyệt — cùng một máy móc mà mã của bạn thực sự chạy — và tô màu từng bit theo vùng mà nó thuộc về.
Bản thân quá trình mã hóa tuân theo ba bước và công cụ này sẽ thực hiện tất cả các bước đó thay vì chỉ hiển thị các bit cuối cùng. Đầu tiên, chuẩn hóa: số được viết lại thành 1.mantissa × 2^số mũ, với chính xác một chữ số khác 0 trước điểm nhị phân (các số quá nhỏ để có thể xử lý dưới mức bình thường thay vào đó, không có số 1 ngầm định). Thứ hai, độ lệch số mũ: vì trường số mũ phải lưu trữ cả số mũ dương và số mũ âm dưới dạng số không dấu, nên độ lệch cố định (127 cho độ chính xác đơn, 1023 cho độ chính xác kép) được thêm vào trước khi trường được viết ra dưới dạng nhị phân. Thứ ba, phần định trị phân số được mở rộng từng chút một bằng phương pháp cổ điển “nhân với hai, lấy phần nguyên làm bit tiếp theo, giữ phần còn lại” - lặp lại cho đến khi trường phần định trị đầy, tại thời điểm đó, các bit còn lại sẽ quyết định xem kết quả có làm tròn lên hay không (làm tròn nửa thành chẵn, mặc định của IEEE-754).
Đây chính xác là lý do tại sao một số bình thường như 0,1 không được lưu trữ chính xác. Trong hệ nhị phân, 0,1 là một phân số lặp lại (0,0001100110011…, mãi mãi), vì vậy không có phần định trị hữu hạn nào có thể chứa nó một cách chính xác - nó phải được làm tròn ở đâu đó. Mã hóa 0,1 dưới dạng float 32 bit và đọc lại các bit và bạn không nhận lại 0,1: bạn nhận được chính xác 0,100000001490116119384765625. Độ chính xác kép có thêm 29 bit mantissa để hoạt động, do đó sai số làm tròn của nó nhỏ hơn nhiều, nhưng cũng không bằng 0 - 0,1 đối với gấp đôi 64 bit chính xác là 0,1000000000000000055511151231257827021181583404541015625. Công cụ này tính toán giá trị được lưu trữ chính xác đó bằng số học số nguyên lớn (không có phím tắt dấu phẩy động) để khoảng cách giữa nội dung bạn nhập và nội dung phần cứng thực sự lưu giữ không bao giờ bị ẩn hoặc gần đúng.
Các giá trị đặc biệt nhận được các mẫu bit chính xác, dành riêng thay vì mã hóa thông thường: số 0 và số 0 âm có các bit số mũ và phần định trị bằng 0 (chỉ có bit dấu là khác nhau), ±Infinity có các bit số mũ tất cả một với phần định trị hoàn toàn bằng 0 và NaN có các bit số mũ tất cả một với ít nhất một bộ bit định trị. Mọi thứ ở đây chạy cục bộ trong trình duyệt của bạn — không có nội dung nào bạn nhập được tải lên ở bất kỳ đâu — điều này làm cho nơi này trở thành một nơi an toàn để xây dựng trực giác thực sự về các lỗi dấu phẩy động: tại sao `0,1 + 0,2 !== 0,3` trong hầu hết mọi ngôn ngữ lập trình, tại sao họa tiết float32 trong mã đồ họa lại mất đi độ chính xác mà float64 sẽ không làm được và tại sao mã tài chính nói chung nên tránh hoàn toàn dấu phẩy động nhị phân.