Đọc qua đặc tả ECMAScript 5.1 , +0
và-0
được phân biệt.
Tại sao sau đó không +0 === -0
đánh giá true
?
Object.is
để phân biệt +0 và -0
Đọc qua đặc tả ECMAScript 5.1 , +0
và-0
được phân biệt.
Tại sao sau đó không +0 === -0
đánh giá true
?
Object.is
để phân biệt +0 và -0
Câu trả lời:
JavaScript sử dụng tiêu chuẩn IEEE 754 để thể hiện các con số. Từ Wikipedia :
Ký 0 là 0 với một dấu hiệu liên quan. Trong số học thông thường, −0 = +0 = 0. Tuy nhiên, trong điện toán, một số biểu diễn số cho phép tồn tại hai số không, thường được ký hiệu là −0 (số 0 âm) và +0 (số 0 dương) . Điều này xảy ra trong một số biểu diễn số đã ký cho số nguyên và trong hầu hết các biểu diễn số dấu phẩy động. Số 0 thường được mã hóa là +0, nhưng có thể được biểu thị bằng +0 hoặc −0.
Tiêu chuẩn IEEE 754 cho số học dấu phẩy động (hiện được sử dụng bởi hầu hết các máy tính và ngôn ngữ lập trình hỗ trợ số dấu phẩy động) yêu cầu cả +0 và −0. Các số 0 có thể được coi là một biến thể của dòng số thực mở rộng sao cho 1/0 = và 1 / + 0 = +, chia cho 0 chỉ không được xác định cho ± 0 / ± 0 và ± ∞ / ± .
Bài viết chứa thông tin thêm về các đại diện khác nhau.
Vì vậy, đây là lý do tại sao, về mặt kỹ thuật, cả hai số không phải được phân biệt.
Tuy nhiên,
+0 === -0
đánh giá là đúng. Tại sao vậy (...) ?
Hành vi này được xác định rõ ràng trong phần 11.9.6 , Thuật toán so sánh bình đẳng nghiêm ngặt (phần nhấn mạnh của tôi):
Sự so sánh
x === y
, ở đâux
vày
là các giá trị, tạo ra đúng hay sai . So sánh như vậy được thực hiện như sau:(...)
Nếu Loại (x) là Số, thì
- Nếu x là NaN, trả về false.
- Nếu y là NaN, trả về false.
- Nếu x là giá trị Số giống như y, trả về true.
- Nếu x là +0 và y là −0, trả về true.
- Nếu x là −0 và y là +0, trả về true.
- Trả lại sai.
(...)
(Điều tương tự giữ cho +0 == -0
btw.)
Có vẻ hợp lý để đối xử +0
và -0
như nhau. Nếu không, chúng tôi sẽ phải tính đến điều này trong mã của chúng tôi và cá nhân tôi không muốn làm điều đó;)
Ghi chú:
ES2015 giới thiệu một phương pháp so sánh mới , Object.is
. Object.is
phân biệt rõ ràng giữa -0
và +0
:
Object.is(-0, +0); // false
1/0 === Infinity; // true
và 1/-0 === -Infinity; // true
.
1 === 1
và +0 === -0
nhưng 1/+0 !== 1/-0
. Thật kỳ lạ!
+0 !== -0
;) Điều đó thực sự có thể tạo ra vấn đề.
0 !== +0
/ 0 !== -0
, điều này thực sự cũng sẽ tạo ra vấn đề!
Tôi sẽ thêm câu trả lời này vì tôi đã bỏ qua nhận xét của @ user113716.
Bạn có thể kiểm tra -0 bằng cách làm điều này:
function isMinusZero(value) {
return 1/value === -Infinity;
}
isMinusZero(0); // false
isMinusZero(-0); // true
e±308
, số của bạn chỉ có thể được biểu diễn dưới dạng không chuẩn hóa và các triển khai khác nhau có ý kiến khác nhau về nơi có hỗ trợ chúng hay không. Vấn đề là, trên một số máy ở một số chế độ dấu phẩy động, số của bạn được thể hiện dưới dạng -0
và trên các máy khác là số không chuẩn hóa 0.000000000000001e-308
. Những chiếc phao như vậy, rất vui
Tôi vừa bắt gặp một ví dụ trong đó +0 và -0 hành xử rất khác nhau thực sự:
Math.atan2(0, 0); //returns 0
Math.atan2(0, -0); //returns Pi
Hãy cẩn thận: ngay cả khi sử dụng Math.round trên một số âm như -0.0001, nó thực sự sẽ là -0 và có thể làm hỏng một số tính toán tiếp theo như được hiển thị ở trên.
Cách nhanh và bẩn để khắc phục điều này là làm smth như:
if (x==0) x=0;
hoặc chỉ:
x+=0;
Điều này chuyển đổi số thành +0 trong trường hợp nó là -0.
Trong tiêu chuẩn IEEE 754 được sử dụng để thể hiện loại Số trong JavaScript, dấu hiệu được biểu thị bằng một bit (số 1 biểu thị số âm).
Kết quả là, tồn tại cả giá trị âm và giá trị dương cho mỗi số đại diện, bao gồm 0
.
Đây là lý do tại sao cả hai -0
và +0
tồn tại.
Trả lời tiêu đề gốc Are +0 and -0 the same?
:
brainslugs83
(trong các bình luận trả lời bởi Spudley
) đã chỉ ra một trường hợp quan trọng trong đó +0 và -0 trong JS không giống nhau - được thực hiện như hàm:
var sign = function(x) {
return 1 / x === 1 / Math.abs(x);
}
Điều này sẽ, ngoài tiêu chuẩn Math.sign
trả về dấu chính xác là +0 và -0.
Có hai giá trị có thể (biểu diễn bit) cho 0. Đây không phải là duy nhất. Đặc biệt là trong số điểm nổi điều này có thể xảy ra. Đó là bởi vì số dấu phẩy động thực sự được lưu trữ như một loại công thức.
Số nguyên có thể được lưu trữ theo những cách riêng biệt quá. Bạn có thể có một giá trị số với một bit đăng nhập bổ sung, vì vậy trong không gian 16 bit, bạn có thể lưu trữ giá trị nguyên 15 bit và bit bit. Trong biểu diễn này, cả giá trị 1000 (hex) và 0000 đều bằng 0, nhưng một trong số chúng là +0 và giá trị kia là -0.
Điều này có thể tránh được bằng cách trừ 1 từ giá trị số nguyên để nó nằm trong khoảng từ -1 đến -2 ^ 16, nhưng điều này sẽ bất tiện.
Một cách tiếp cận phổ biến hơn là lưu trữ số nguyên trong 'hai bổ sung', nhưng rõ ràng ECMAscript đã chọn không. Trong phương pháp này, số từ 0000 đến 7FFF dương. Các số âm bắt đầu từ FFFF (-1) đến 8000.
Tất nhiên, các quy tắc tương tự cũng áp dụng cho các số nguyên lớn hơn, nhưng tôi không muốn F của mình bị hao mòn. ;)
+0 === -0
hơi kỳ lạ. Bởi vì bây giờ chúng ta có 1 === 1
và +0 === -0
nhưng 1/+0 !== 1/-0
...
+0 === -0
mặc dù hai biểu diễn bit là khác nhau.
Tôi đổ lỗi cho phương pháp So sánh bình đẳng nghiêm ngặt ('==='). Nhìn vào phần 4d
xem 7.2.13 So sánh bình đẳng nghiêm ngặt về đặc điểm kỹ thuật
Wikipedia có một bài viết hay để giải thích hiện tượng này: http://en.wikipedia.org/wiki/Sign_zero
Tóm lại, cả +0 và -0 đều được xác định trong thông số kỹ thuật của dấu phẩy động của IEEE. Cả hai đều khác biệt về mặt kỹ thuật từ 0 mà không có dấu, đó là một số nguyên, nhưng trong thực tế, tất cả chúng đều ước tính bằng 0, vì vậy sự khác biệt có thể được bỏ qua cho tất cả các mục đích thực tế.