Có +0 và -0 giống nhau không?


171

Đọc qua đặc tả ECMAScript 5.1 , +0-0 được phân biệt.

Tại sao sau đó không +0 === -0đánh giá true?


bản sao có thể có của Phân biệt +0 và -0
GolezTrol

6
Lưu ý rằng trong ES2015, bạn có thể sử dụng Object.isđể phân biệt +0 và -0
Benjamin Gruenbaum

Trích dẫn David Flanagan từ JS hướng dẫn dứt khoát : Dòng chảy xảy ra khi kết quả của một phép toán số gần bằng 0 hơn số đại diện nhỏ nhất. Trong trường hợp này, JavaScript trả về 0. Nếu dòng chảy xảy ra từ một số âm, JavaScript trả về một giá trị đặc biệt được gọi là số 0 âm.
RBT

Câu trả lời:


193

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)+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, ở đâu xylà 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ì

    1. Nếu x là NaN, trả về false.
    2. Nếu y là NaN, trả về false.
    3. Nếu x là giá trị Số giống như y, trả về true.
    4. Nếu x là +0 và y là −0, trả về true.
    5. Nếu x là −0 và y là +0, trả về true.
    6. Trả lại sai.

(...)

(Điều tương tự giữ cho +0 == -0btw.)

Có vẻ hợp lý để đối xử +0-0như 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.isphân biệt rõ ràng giữa -0+0:

Object.is(-0, +0); // false

15
Thật vậy 1/0 === Infinity; // true1/-0 === -Infinity; // true.
dùng113716

48
Vì vậy, chúng tôi có 1 === 1+0 === -0nhưng 1/+0 !== 1/-0. Thật kỳ lạ!
Randomblue

8
@Random: Tôi nghĩ nó chắc chắn tốt hơn +0 !== -0;) Điều đó thực sự có thể tạo ra vấn đề.
Felix Kling

@FelixKling, hoặc 0 !== +0/ 0 !== -0, điều này thực sự cũng sẽ tạo ra vấn đề!
Yanick Rochon

5
Trên thực tế, mô hình hành vi này giới hạn tính toán trong toán học. Ví dụ, hàm 1 / x có giá trị vô cực bằng 0, tuy nhiên, nó được tách ra nếu chúng ta tiếp cận 0 từ cực dương của phía âm; trong cái trước, kết quả là + inf, trong cái sau, -inf.
Agoston Horvath

19

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

6
Có lẽ cũng nên kiểm tra == 0, isMinusZero (-1e-323) ở trên trả về đúng!
Chris

1
@Chris, giới hạn của số mũ chính xác kép là 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 -0và 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
franespase

Điều này cũng có thể hoạt động với các ngôn ngữ khác (Tôi đã thử nghiệm cho C và điều này hoạt động)
Mukul Kumar

11

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.


Cảm ơn. Thật kỳ lạ khi thêm số 0 sẽ khắc phục vấn đề tôi gặp phải. "Nếu vẫn thất bại, thêm số không." Một bài học cho cuộc sống.
microsis

Tôi cũng vừa gặp điều này trong Math.atan (y / x), điều này (có lẽ đáng ngạc nhiên) có thể xử lý "y / x" tích cực hoặc tiêu cực, ngoại trừ nó đưa ra câu trả lời sai trong trường hợp x là -0. Thay thế "x" bằng "(x + 0)" sẽ sửa nó.
Jacob C. nói Phục hồi lại

5

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+0tồn tại.


3
Bổ sung của hai cũng sử dụng một chút cho dấu hiệu, nhưng chỉ có một số không (dương).
Felix Kling

1
Có nhưng trong phần bù của Two, bit âm cũng là một phần của giá trị, vì vậy một khi bạn đặt bit âm, nó không còn là 0 nữa.
Arnaud Le Blanc

3

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.signtrả về dấu chính xác là +0 và -0.


2

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. ;)


4
Nhưng bạn không thấy điều đó +0 === -0hơi kỳ lạ. Bởi vì bây giờ chúng ta có 1 === 1+0 === -0nhưng 1/+0 !== 1/-0...
Randomblue

2
Tất nhiên +0 là -0. Cả hai đều không có gì. Nhưng có một sự khác biệt rất lớn giữa + vô cực và vô cực, phải không? Những số vô định đó thậm chí có thể là lý do tại sao ECMA hỗ trợ cả +0 và -1.
GolezTrol

Bạn không giải thích tại sao +0 === -0mặc dù hai biểu diễn bit là khác nhau.
Randomblue

1
+0 là -0 là 0, không có gì, nada, niente. Nó có ý nghĩa rằng họ là như nhau. Tại sao bầu trời màu xanh? 4 + 3 cũng giống như 1 + 6, mặc dù các cách biểu diễn khác nhau. Chúng có các biểu diễn khác nhau (và do đó có giá trị bit khác nhau), nhưng khi so sánh chúng được xử lý như cùng một số 0, chúng là.
GolezTrol

1
Chúng không giống nhau. Xem stackoverflow.com/questions/7223717/differentiating-0-and-0 để biết ví dụ cho thấy điều đó.
Randomblue

2

Chúng ta có thể sử dụng Object.isđể phân biệt +0 và -0, và một điều nữa , NaN==NaN.

Object.is(+0,-0) //false

Object.is(NaN,NaN) //true


0

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ế.


2
Điều đó không hoàn toàn chính xác - 1 / -0 == 1/0 ước tính thành false trong javascript chẳng hạn. Họ không "đánh giá" thành số 0 không dấu, vì không có khái niệm nào như "số nguyên không dấu" trong IEEE 754.
BrainSlugs83
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.