Bạn đang tràn năng lực của loại số JavaScript, xem §8.5 of the spec để biết chi tiết. Những ID đó sẽ cần phải là chuỗi.
Điểm nổi chính xác kép IEEE-754 (loại sử dụng JavaScript số) không thể đại diện chính xác tất cả số (tất nhiên). Nổi tiếng, 0.1 + 0.2 == 0.3
là sai. Điều đó có thể ảnh hưởng đến số nguyên giống như nó ảnh hưởng đến các số phân số; nó bắt đầu khi bạn nhận được trên 9,007,199,254,740,991 (Number.MAX_SAFE_INTEGER
).
Ngoài Number.MAX_SAFE_INTEGER + 1
(9007199254740992
), định dạng điểm nổi IEEE-754 không thể đại diện cho mọi số nguyên liên tiếp nữa. 9007199254740991 + 1
là 9007199254740992
, nhưng 9007199254740992 + 1
là cũng9007199254740992
vì không thể đại diện cho 9007199254740993
ở định dạng. Tiếp theo có thể là 9007199254740994
. Sau đó, 9007199254740995
không thể, nhưng 9007199254740996
có thể.
Lý do là chúng tôi đã hết bit, vì vậy chúng tôi không còn bit 1 giây nữa; bit thứ tự thấp nhất hiện nay đại diện cho bội số của 2. Cuối cùng, nếu chúng ta tiếp tục, chúng ta mất bit đó và chỉ làm việc trong bội số của 4. Và cứ thế.
Giá trị của bạn là cũng cao hơn ngưỡng đó và do đó chúng được làm tròn thành giá trị thể hiện gần nhất.
Nếu bạn tò mò về các bit, đây là những gì sẽ xảy ra: Một IEEE-754 nhị phân đúp chính xác số dấu chấm động có một chút dấu hiệu, 11 bit của số mũ (trong đó xác định quy mô tổng thể về số , như là một sức mạnh của 2 [bởi vì đây là một định dạng nhị phân]), và 52 bit của significand (nhưng định dạng rất thông minh nó được 53 bit chính xác trong số 52 bit đó). Cách số mũ được sử dụng phức tạp (described here), nhưng trong rất thuật ngữ mơ hồ, nếu chúng ta thêm một vào số mũ, giá trị của significand được tăng gấp đôi, vì số mũ được sử dụng cho lũy thừa 2 (một lần nữa, hãy báo trước ở đó, nó không trực tiếp, có sự thông minh trong đó).
Vì vậy, chúng ta hãy nhìn vào giá trị 9007199254740991
(aka, Number.MAX_SAFE_INTEGER
):
+−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− sign bit
/ +−−−−−−−+−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− exponent
// | +−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−+− significand
// |/ |
0 10000110011 1111111111111111111111111111111111111111111111111111
= 9007199254740991 (Number.MAX_SAFE_INTEGER)
Đó giá trị số mũ, 10000110011
, có nghĩa là mỗi lần chúng tôi thêm một đến significand, số đại diện đi lên bằng 1 (các toàn bộ số 1, chúng tôi đã mất khả năng biểu diễn số phân số sớm hơn nhiều).
Nhưng bây giờ điều đó có nghĩa là đầy. Để vượt qua con số đó, chúng ta phải tăng số mũ, có nghĩa là nếu chúng ta thêm số mũ vào giá trị và giá trị của số được biểu thị tăng lên 2, không phải 1 (vì số mũ được áp dụng cho 2, cơ sở của số này số dấu chấm động nhị phân):
+−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− sign bit
/ +−−−−−−−+−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− exponent
// | +−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−+− significand
// |/ |
0 10000110100 0000000000000000000000000000000000000000000000000000
= 9007199254740992 (Number.MAX_SAFE_INTEGER + 1)
Vâng, đó là okay, vì 9007199254740991 + 1
là 9007199254740992
anyway. Nhưng! Chúng tôi không thể đại diện cho 9007199254740993
. Chúng tôi đã hết bit. Nếu chúng tôi chỉ thêm 1 vào mức độ có nghĩa là, nó thêm 2 vào giá trị:
+−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− sign bit
/ +−−−−−−−+−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− exponent
// | +−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−+− significand
// |/ |
0 10000110100 0000000000000000000000000000000000000000000000000001
= 9007199254740994 (Number.MAX_SAFE_INTEGER + 3)
Định dạng không thể đại diện cho số lẻ nữa khi chúng tôi tăng giá trị, số mũ quá lớn.
Cuối cùng, chúng tôi chạy ra khỏi significand bit một lần nữa và phải tăng số mũ, vì vậy chúng tôi kết thúc chỉ có thể đại diện cho bội số của 4. Sau đó bội số của 8. Sau đó bội số của 16. Và như vậy.
Cảm ơn tất cả các câu trả lời hữu ích nhanh chóng, tôi ước tôi có thể đánh dấu tất cả 3 là câu trả lời chính thức. – Jaanus