Apakah +0 dan -0 sama?


172

Membaca spesifikasi ECMAScript 5.1 , +0dan -0dibedakan.

Lalu mengapa +0 === -0harus dievaluasi true?


kemungkinan duplikat dari Differensiasi +0 dan -0
GolezTrol

6
Perhatikan bahwa dalam ES2015 Anda dapat menggunakan Object.isuntuk membedakan +0 dan -0
Benjamin Gruenbaum

Mengutip David Flanagan dari JS panduan definitif : Underflow terjadi ketika hasil operasi numerik lebih dekat ke nol daripada angka keterwakilan terkecil. Dalam hal ini, JavaScript mengembalikan 0. Jika underflow terjadi dari angka negatif, JavaScript mengembalikan nilai khusus yang dikenal sebagai "nol negatif."
RBT

Jawaban:


194

JavaScript menggunakan standar IEEE 754 untuk merepresentasikan angka. Dari Wikipedia :

Tanda nol adalah nol dengan tanda terkait. Dalam aritmatika biasa, −0 = +0 = 0. Namun, dalam komputasi, beberapa representasi angka memungkinkan adanya dua nol, sering dilambangkan dengan −0 (nol negatif) dan +0 (nol positif) . Ini terjadi di beberapa representasi angka yang ditandatangani untuk bilangan bulat, dan di sebagian besar representasi angka floating point. Angka 0 biasanya dikodekan sebagai +0, tetapi dapat direpresentasikan dengan +0 atau −0.

Standar IEEE 754 untuk aritmatika floating point (saat ini digunakan oleh sebagian besar komputer dan bahasa pemrograman yang mendukung angka floating point) membutuhkan +0 dan −0. Nol dapat dianggap sebagai varian dari garis bilangan real yang diperluas sehingga 1 / −0 = −∞ dan 1 / + 0 = + ∞, pembagian dengan nol hanya tidak ditentukan untuk ± 0 / ± 0 dan ± ∞ / ± ∞ .

Artikel tersebut berisi informasi lebih lanjut tentang representasi yang berbeda.

Jadi inilah alasan mengapa, secara teknis, kedua nol harus dibedakan.

Namun, +0 === -0mengevaluasi ke true. Mengapa demikian (...) ?

Perilaku ini secara eksplisit didefinisikan dalam bagian 11.9.6 , Algoritma Perbandingan Kesetaraan Ketat (penekanan sebagian milik saya):

Perbandingan x === y, di mana xdan yadalah nilai, menghasilkan benar atau salah . Perbandingan semacam itu dilakukan sebagai berikut:

(...)

  • Jika Tipe (x) adalah Angka, maka

    1. Jika x adalah NaN, kembalikan salah.
    2. Jika y adalah NaN, kembalikan salah.
    3. Jika x adalah nilai Angka yang sama dengan y, kembalikan benar.
    4. Jika x adalah +0 dan y adalah −0, kembalikan true.
    5. Jika x adalah −0 dan y adalah +0, kembalikan true.
    6. Kembali salah

(...)

(Hal yang sama berlaku untuk +0 == -0btw.)

Tampaknya secara logis untuk memperlakukan +0dan -0setara. Kalau tidak, kita harus mempertimbangkan ini dalam kode kita dan saya, secara pribadi, tidak ingin melakukan itu;)


catatan:

ES2015 memperkenalkan metode perbandingan baru Object.is,. Object.issecara eksplisit membedakan antara -0dan +0:

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

15
Memang 1/0 === Infinity; // truedan 1/-0 === -Infinity; // true.
user113716

48
Jadi kita punya 1 === 1dan +0 === -0tapi 1/+0 !== 1/-0. Aneh sekali!
Randomblue

8
@ Acak: Saya pikir itu pasti lebih baik daripada +0 !== -0;) Itu benar-benar bisa membuat masalah.
Felix Kling

@ Feliksling, atau 0 !== +0/ 0 !== -0, yang memang akan membuat masalah juga!
Yanick Rochon

5
Sebenarnya, model perilaku ini membatasi perhitungan dalam matematika. Misalnya fungsi 1 / x memiliki nilai tak terhingga dalam 0, namun, dipisahkan jika kita mendekati 0 dari sisi positif sisi negatif; di yang pertama, hasilnya adalah + inf, di yang terakhir, -inf.
Agoston Horvath

19

Saya akan menambahkan ini sebagai jawaban karena saya mengabaikan komentar @ user113716.

Anda dapat menguji -0 dengan melakukan ini:

function isMinusZero(value) {
  return 1/value === -Infinity;
}

isMinusZero(0); // false
isMinusZero(-0); // true

6
Mungkin sebaiknya memeriksa == 0 juga, isMinusZero (-1e-323) di atas mengembalikan true!
Chris

1
@ Chris, batas eksponen presisi ganda adalah e±308, nomor Anda hanya dapat diwakili dalam bentuk denormalized dan implementasi yang berbeda memiliki pendapat berbeda tentang di mana mereka mendukung sama sekali atau tidak. Intinya adalah, pada beberapa mesin dalam beberapa mode floating point nomor Anda direpresentasikan sebagai -0dan pada yang lain sebagai nomor denormalized 0.000000000000001e-308. Mengapung seperti itu, sangat menyenangkan
titik lemah

Ini mungkin bekerja untuk bahasa lain juga (saya menguji C dan ini berhasil)
Mukul Kumar

12

Saya baru saja menemukan contoh di mana +0 dan -0 berperilaku sangat berbeda:

Math.atan2(0, 0);  //returns 0
Math.atan2(0, -0); //returns Pi

Hati-hati: walaupun menggunakan Math.round pada angka negatif seperti -0,0001, sebenarnya akan menjadi -0 dan dapat mengacaukan beberapa perhitungan selanjutnya seperti yang ditunjukkan di atas.

Cara cepat dan kotor untuk memperbaikinya adalah dengan melakukan sesuatu seperti:

if (x==0) x=0;

atau hanya:

x+=0;

Ini mengonversi angka menjadi +0 jika -0.


Terima kasih. Sangat aneh bagaimana menambahkan nol akan memperbaiki masalah yang saya temui. "Jika semuanya gagal, tambahkan nol." Pelajaran seumur hidup.
Microsis

Saya baru saja menemukan ini dalam Math.atan (y / x) juga, yang (mungkin mengejutkan) dapat menangani positif atau negatif tak terbatas "y / x", kecuali itu memberikan jawaban yang salah dalam kasus di mana x adalah -0. Mengganti "x" dengan "(x + 0)" memperbaikinya.
Jacob C. mengatakan Reinstate Monica

5

Dalam standar IEEE 754 yang digunakan untuk mewakili tipe angka dalam JavaScript, tanda diwakili oleh sedikit (angka 1 menunjukkan angka negatif).

Akibatnya, ada nilai negatif dan positif untuk setiap angka yang dapat diwakili, termasuk 0.

Inilah sebabnya mengapa baik -0dan +0eksis.


3
Pelengkap dua juga menggunakan sedikit untuk tanda, tetapi hanya memiliki satu nol (positif).
Felix Kling

1
Ya tetapi dalam komplemen Two's bit negatif juga merupakan bagian dari nilai, jadi setelah Anda mengatur bit negatif, itu bukan nol lagi.
Arnaud Le Blanc

3

Menjawab judul aslinya Are +0 and -0 the same?:

brainslugs83(dalam komentar jawaban oleh Spudley) menunjukkan kasus penting di mana +0 dan -0 di JS tidak sama - diimplementasikan sebagai fungsi:

var sign = function(x) {
    return 1 / x === 1 / Math.abs(x);
}

Ini akan, selain standar Math.signmengembalikan tanda yang benar dari +0 dan -0.


2

Ada dua nilai yang mungkin (representasi bit) untuk 0. Ini tidak unik. Terutama dalam angka floating point ini dapat terjadi. Itu karena angka floating point sebenarnya disimpan sebagai semacam rumus.

Integer dapat disimpan dengan cara yang terpisah juga. Anda dapat memiliki nilai numerik dengan bit tanda tambahan, jadi dalam ruang 16 bit, Anda dapat menyimpan nilai integer 15 bit dan bit tanda. Dalam representasi ini, nilai 1000 (hex) dan 0000 keduanya adalah 0, tetapi salah satunya adalah +0 dan yang lainnya adalah -0.

Ini bisa dihindari dengan mengurangi 1 dari nilai integer sehingga berkisar antara -1 hingga -2 ^ 16, tetapi ini akan merepotkan.

Pendekatan yang lebih umum adalah menyimpan bilangan bulat dalam 'dua komplemen', tetapi tampaknya ECMAscript memilih untuk tidak melakukannya. Dalam metode ini angka berkisar dari 0000 hingga 7FFF positif. Angka negatif mulai dari FFFF (-1) hingga 8000.

Tentu saja, aturan yang sama juga berlaku untuk bilangan bulat yang lebih besar, tapi saya tidak ingin F saya usang. ;)


4
Tapi jangan Anda menemukan itu +0 === -0agak aneh. Karena sekarang kita punya 1 === 1dan +0 === -0tapi 1/+0 !== 1/-0...
Randomblue

2
Tentu saja +0 adalah -0. Keduanya bukan apa-apa. Tapi ada perbedaan besar antara + infinity dan -infinity, kan? Angka-angka inifinity itu bahkan mungkin menjadi alasan mengapa ECMA mendukung +0 dan -1.
GolezTrol

Anda tidak menjelaskan mengapa +0 === -0meskipun representasi sedikit berbeda.
Randomblue

1
+0 adalah -0 adalah 0, tidak ada, nada, niente. Masuk akal jika mereka sama. Mengapa langit Berwarna biru? 4 + 3 juga sama dengan 1 + 6, meskipun representasinya berbeda. Mereka memiliki representasi yang berbeda (dan dengan demikian nilai bit yang berbeda), tetapi ketika dibandingkan mereka ditangani sebagai nol yang sama, yaitu mereka.
GolezTrol

1
Mereka tidak sama. Lihat stackoverflow.com/questions/7223717/differentiating-0-and-0 untuk contoh yang menunjukkan hal itu.
Randomblue

2

Kita dapat menggunakan Object.isuntuk membedakan +0 dan -0, dan satu hal lagi NaN==NaN,.

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

Object.is(NaN,NaN) //true

1

Saya akan menyalahkannya pada metode Perbandingan Kesetaraan Ketat ('==='). Lihatlah bagian 4d masukkan deskripsi gambar di sini

lihat 7.2.13 Perbandingan Kesetaraan Ketat pada spesifikasi


0

Wikipedia memiliki artikel yang bagus untuk menjelaskan fenomena ini: http://en.wikipedia.org/wiki/Signed_zero

Singkatnya, itu +0 dan -0 didefinisikan dalam spesifikasi IEEE floating point. Keduanya secara teknis berbeda dari 0 tanpa tanda, yang merupakan bilangan bulat, tetapi dalam praktiknya semuanya bernilai nol, sehingga perbedaannya dapat diabaikan untuk semua tujuan praktis.


2
Itu tidak sepenuhnya benar - 1 / -0 == 1/0 dievaluasi menjadi false dalam javascript misalnya. Mereka tidak "mengevaluasi" ke nol ajaib bertanda, karena tidak ada konsep seperti seperti "nol bertanda bulat" di IEEE 754.
BrainSlugs83
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.