Máy tính lưu số trong những ô có độ dài cố định, nên mỗi ô chỉ đếm được tới một giới hạn. Ô 32 bit có dấu dừng ở 2.147.483.647, ô 64 bit dừng ở khoảng 9,2 × 10¹⁸. Vượt quá giới hạn, con số "tràn" và quay về số âm hoặc về 0, và đó là nguồn gốc của những sự cố như bộ đếm lượt xem bị vỡ năm 2014, sự cố năm 2038 hay việc thế giới hết địa chỉ IPv4.
Mỗi bit thêm vào là nhân đôi
Máy tính ghi số bằng bit, mỗi bit là 0 hoặc 1. Với n bit, có 2ⁿ tổ hợp khác nhau. Đây là một bậc thang luỹ tiến thuần tuý: thêm một bit là gấp đôi khả năng đếm.
| Số bit | Số giá trị (2ⁿ) | Không dấu: từ 0 tới | Có dấu: lớn nhất | Dùng ở đâu |
|---|---|---|---|---|
| 8 | 256 | 255 | 127 | một byte, mã màu mỗi kênh đỏ, lục, lam |
| 16 | 65.536 | 65.535 | 32.767 | số cổng mạng, âm thanh CD |
| 32 | khoảng 4,29 tỷ | 4.294.967.295 | 2.147.483.647 | địa chỉ IPv4, thời gian Unix kiểu cũ |
| 64 | khoảng 1,8 × 10¹⁹ | 18.446.744.073.709.551.615 | 9.223.372.036.854.775.807 | hầu hết máy tính, điện thoại hiện nay |
| 128 | khoảng 3,4 × 10³⁸ | một số có 39 chữ số | — | địa chỉ IPv6, mã định danh ngẫu nhiên |
"Có dấu" nghĩa là dành ra một phần để ghi số âm, nên số dương lớn nhất chỉ còn một nửa. Cách phổ biến nhất (gọi là bù hai) có một hệ quả lạ: cộng 1 vào số dương lớn nhất thì ra ngay số âm nhỏ nhất. 2.147.483.647 + 1 thành −2.147.483.648. Hiện tượng đó gọi là tràn số.
Mẹo nhẩm: 2¹⁰ = 1.024 ≈ 10³. Vậy 2³² = 2² × (2¹⁰)³ ≈ 4 × 10⁹, tức khoảng 4 tỷ. 2⁶⁴ ≈ 16 × 10¹⁸. 2¹²⁸ ≈ 256 × 10³⁶ ≈ 3 × 10³⁸ (con số thật là 3,4 × 10³⁸, sai số tích luỹ vì 1.024 lớn hơn 1.000 một chút).
Năm 2014: bộ đếm lượt xem chạm trần
Tháng 12 năm 2014, YouTube thông báo một video ca nhạc Hàn Quốc đã vượt 2.147.483.647 lượt xem, giới hạn của bộ đếm 32 bit có dấu mà hệ thống dùng lúc thiết kế. Khi xây dựng, không ai nghĩ một video lại được xem hơn hai tỷ lần. YouTube đã chuyển bộ đếm sang 64 bit trước khi con số tràn, và đăng một lời đùa trên trang của mình về việc này.
Câu chuyện nhỏ này minh hoạ một quy luật lớn: giới hạn được chọn theo những gì người thiết kế tưởng tượng được lúc đó. Mà thứ gì tăng theo cấp số nhân, như lượng người dùng internet, thì sớm muộn sẽ vượt mọi tưởng tượng ban đầu.
Sự cố năm 2038
Rất nhiều hệ thống máy tính đo thời gian theo kiểu Unix: đếm số giây kể từ 0 giờ ngày 1 tháng 1 năm 1970 theo giờ quốc tế (UTC). Nếu bộ đếm đó là số nguyên 32 bit có dấu, nó sẽ đạt 2.147.483.647 vào 03:14:07 UTC ngày 19 tháng 1 năm 2038, tức 10 giờ 14 phút 7 giây sáng theo giờ Việt Nam. Giây tiếp theo, số tràn thành âm, và máy hiểu là ngày 13 tháng 12 năm 1901.
Bạn có thể tự kiểm: 2.147.483.647 giây chia cho 31.556.952 giây mỗi năm (năm trung bình theo lịch Gregory) được khoảng 68,05 năm. Cộng vào 1970 là đầu năm 2038.
Đa số máy tính và điện thoại hiện nay đã dùng thời gian 64 bit, nên an toàn. Nỗi lo nằm ở những thiết bị nhúng chạy hàng chục năm không ai cập nhật: bộ điều khiển công nghiệp, thiết bị mạng cũ, hệ thống trong xe hơi, phần mềm và cơ sở dữ liệu lưu ngày tháng dạng 32 bit. Chuyển sang 64 bit thì giới hạn lùi tới khoảng 292 tỷ năm sau, lâu hơn tuổi vũ trụ khoảng hai mươi lần.
Người lớn tuổi sẽ nhớ "sự cố Y2K" năm 2000, khi nhiều phần mềm chỉ lưu năm bằng hai chữ số. Nhờ được chuẩn bị kỹ, những năm cuối thập niên 1990 các doanh nghiệp đã sửa phần lớn hệ thống, và ngày đầu năm 2000 trôi qua không có sự cố lớn. Sự cố 2038 là cùng một kiểu vấn đề, chỉ khác ở cơ số.
Thế giới hết địa chỉ IPv4
Mỗi thiết bị kết nối internet cần một địa chỉ. Chuẩn IPv4, thiết kế từ đầu thập niên 1980, dùng địa chỉ 32 bit, tức khoảng 4,29 tỷ địa chỉ. Khi đó con số này có vẻ vô tận. Nhưng dân số thế giới đã vượt 8 tỷ, và mỗi người có thể dùng nhiều thiết bị.
Ngày 3 tháng 2 năm 2011, tổ chức quản lý địa chỉ toàn cầu IANA phân phát những khối địa chỉ IPv4 tự do cuối cùng cho các cơ quan khu vực. Tháng 4 cùng năm, cơ quan phụ trách châu Á – Thái Bình Dương (APNIC), nơi Việt Nam thuộc về, cũng chạm tới khối địa chỉ cuối. Từ đó internet sống được nhờ các kỹ thuật cho nhiều thiết bị dùng chung một địa chỉ, như bộ định tuyến ở nhà bạn đang làm.
Giải pháp lâu dài là IPv6 với địa chỉ 128 bit, khoảng 3,4 × 10³⁸ địa chỉ. Con số này lớn tới mức chia đều cho bề mặt Trái Đất (khoảng 5,1 × 10¹⁴ mét vuông) vẫn được khoảng 6,7 × 10²³ địa chỉ mỗi mét vuông. Chỉ thêm 96 bit, tức gấp 2⁹⁶ lần, đã đủ cho mọi nhu cầu có thể tưởng tượng. Đó là sức mạnh của luỹ thừa.
Khi tràn số gây tai nạn thật
- Tên lửa Ariane 5, năm 1996: ngày 4 tháng 6 năm 1996, chuyến bay đầu tiên của tên lửa châu Âu Ariane 5 tự huỷ khoảng 40 giây sau khi rời bệ phóng. Nguyên nhân gốc là một phép chuyển đổi số thực 64 bit sang số nguyên 16 bit bị tràn trong phần mềm dẫn đường, đoạn mã được dùng lại từ Ariane 4, nơi giá trị đó chưa bao giờ đủ lớn để tràn.
- Máy bay Boeing 787, năm 2015: Cục Hàng không Liên bang Mỹ (FAA) ra chỉ thị yêu cầu khởi động lại hệ thống điện của máy bay định kỳ, vì một bộ đếm 32 bit tính theo phần trăm giây sẽ tràn sau khoảng 248 ngày chạy liên tục, có thể làm các bộ điều khiển máy phát điện chuyển sang chế độ an toàn. Bạn tự kiểm được: 2³¹ phần trăm giây = 21.474.836 giây ≈ 248,5 ngày.
Hai ví dụ có chung bài học: phần mềm chạy đúng trong điều kiện cũ có thể sai khi con số lớn hơn mức người viết mã dự tính. Kỹ sư phần mềm vì thế luôn được dạy hỏi một câu đơn giản: "Số này lớn nhất có thể là bao nhiêu, và mình có chắc không?"
Không giới hạn thì sao: số nguyên lớn tuỳ ý
Không phải ngôn ngữ lập trình nào cũng bị giới hạn bởi ô cố định. Python, Ruby hay thư viện số lớn trong Java tự mở rộng số nguyên khi cần, chỉ bị giới hạn bởi bộ nhớ. Trong Python, gõ 2**1000 sẽ ra ngay một số 302 chữ số. Nhờ vậy người ta mới làm việc được với những số nguyên tố có hàng chục triệu chữ số.
Cái giá phải trả là tốc độ. Phép tính trên ô 64 bit được bộ xử lý làm trong một nhịp, còn số lớn tuỳ ý phải xử lý từng mảnh. Vì vậy phần lớn phần mềm vẫn dùng ô cố định, và lập trình viên phải chọn đúng kích thước ngay từ đầu.
Số thực trên máy tính lại có kiểu giới hạn khác: kiểu số thực 64 bit thông dụng biểu diễn được tới khoảng 1,8 × 10³⁰⁸, nhưng chỉ giữ chính xác khoảng 15 tới 17 chữ số có nghĩa. Số nguyên lớn hơn 2⁵³ (khoảng 9 triệu tỷ) bắt đầu bị làm tròn, lý do mã số dài thường phải lưu dưới dạng chuỗi ký tự.
Góc nhìn hôm nay: nhận ra giới hạn trong đời thường
Những con số như 255, 65.535, 2.147.483.647 hay 4.294.967.295 xuất hiện trong đời sống nhiều hơn ta nghĩ. Thấy một phần mềm báo lỗi đúng ở mức 255 ký tự, một bảng tính giới hạn 1.048.576 dòng (bằng 2²⁰), hay một thiết bị cần khởi động lại sau đúng 49,7 ngày (2³² mili giây), bạn sẽ biết ngay đó là một ô số đã đầy.
Bài tập nhỏ: một camera ghi số thứ tự ảnh bằng ô 16 bit không dấu, mỗi ngày chụp 200 ảnh. Bao lâu thì bộ đếm quay về 0? (65.536 ÷ 200 ≈ 328 ngày, chưa tới một năm.) Phép tính đó là cách người làm kỹ thuật tự hỏi trước khi chọn kích thước cho mọi con số.
Câu hỏi thường gặp
Vì sao 2.147.483.647 là số đặc biệt trong máy tính?
Đó là 2³¹ − 1, giá trị lớn nhất của số nguyên 32 bit có dấu. Cộng thêm 1 vào số này, máy tính kiểu cũ sẽ tràn số và ra −2.147.483.648. Euler cũng đã chứng minh nó là số nguyên tố từ năm 1772.
Sự cố năm 2038 là gì?
Nhiều hệ thống đếm thời gian bằng số giây từ ngày 1/1/1970. Nếu bộ đếm là số nguyên 32 bit có dấu, nó sẽ tràn vào 03:14:07 UTC ngày 19/1/2038 và nhảy về năm 1901. Máy dùng thời gian 64 bit thì không bị ảnh hưởng.
IPv6 có bao nhiêu địa chỉ?
IPv6 dùng địa chỉ 128 bit, tức 2¹²⁸, khoảng 3,4 × 10³⁸ địa chỉ. Con số này gấp IPv4 (khoảng 4,29 tỷ địa chỉ) tới 2⁹⁶ lần.
Tràn số là gì?
Tràn số xảy ra khi kết quả phép tính vượt giá trị lớn nhất mà ô nhớ lưu được. Khi đó con số thường quay vòng về số âm hoặc về 0, giống đồng hồ công-tơ-mét xe máy quay về 00000 sau khi chạy hết số.
Máy tính 64 bit đếm được tới bao nhiêu?
Số nguyên 64 bit không dấu đếm tới 18.446.744.073.709.551.615, khoảng 1,8 × 10¹⁹; loại có dấu đếm tới khoảng 9,2 × 10¹⁸. Nếu dùng để đếm giây, giới hạn này tương đương khoảng 292 tỷ năm.