+0 ve -0 aynı mı?


171

Okumak, ECMAScript 5.1 tarifnamede , +0ve-0 ayırt edilir.

Öyleyse neden +0 === -0değerlendiriyor true?



6
ES2015'te Object.is+0 ve -0'ı ayırt etmek için kullanabileceğinizi unutmayın
Benjamin Gruenbaum

David Flanagan'ın JS'den alıntı yapması kesin kılavuz : Sayısal bir işlemin sonucu temsil edilebilir en küçük sayıdan sıfıra yakın olduğunda alt akış meydana gelir. Bu durumda, JavaScript 0 döndürür. Negatif bir sayıdan düşük akış oluşursa, JavaScript “negatif sıfır” olarak bilinen özel bir değer döndürür.
RBT

Yanıtlar:


193

JavaScript sayıları göstermek için IEEE 754 standardını kullanır . Gönderen Vikipedi :

İşaretli sıfır , ilişkili bir işaretle sıfırdır. Sıradan aritmetikte, −0 = +0 = 0. Ancak, hesaplamada, bazı sayı gösterimleri, genellikle −0 (negatif sıfır) ve +0 (pozitif sıfır) ile gösterilen iki sıfırın varlığına izin verir . Bu, tamsayılar için bazı imzalı sayı gösterimlerinde ve çoğu kayan nokta sayısı gösterimlerinde oluşur. 0 sayısı genellikle +0 olarak kodlanır, ancak +0 veya −0 ile temsil edilebilir.

Kayan noktalı aritmetik için IEEE 754 standardı (şu anda kayan noktalı sayıları destekleyen çoğu bilgisayar ve programlama dili tarafından kullanılmaktadır) hem +0 hem de −0 gerektirir. Sıfırlar, 1 / −0 = −∞ ve 1 / + 0 = + ∞ olacak şekilde uzatılmış gerçek sayı çizgisinin bir varyantı olarak düşünülebilir, sıfıra bölme yalnızca ± 0 / ± 0 ve ± ∞ / ± ∞ için tanımlanmamıştır .

Makale, farklı temsiller hakkında daha fazla bilgi içermektedir.

Bu nedenle, teknik olarak, her iki sıfırın da ayırt edilmesi gerekir.

Ancak, +0 === -0doğru olarak değerlendirir. Neden (...) ?

Bu davranış, açık bir şekilde tanımlanır bölüm 11.9.6 , Katı Eşitlik karşılaştırma algoritması (ağırlık kısmı benim):

Değerler x === ynerede xve yolduğunda karşılaştırma doğru veya yanlış üretir . Böyle bir karşılaştırma aşağıdaki gibi yapılır:

(...)

  • Tür (x) Sayı ise, o zaman

    1. X NaN ise false değerini döndürün.
    2. Y NaN ise false değerini döndürün.
    3. X, y ile aynı Sayı değeriyse, true değerini döndürün.
    4. X +0 ve y -0 ise true değerini döndürün.
    5. X −0 ve y +0 ise true değerini döndürün.
    6. Yanlış döndür.

(...)

(Aynı şey +0 == -0btw için de geçerlidir .)

Mantıksal +0ve -0eşit olarak muamele etmek gibi görünüyor . Aksi takdirde bunu kodumuzda dikkate almak zorunda kalacağız ve ben şahsen bunu yapmak istemiyorum;)


Not:

ES2015 yeni bir karşılaştırma yöntemi sunar Object.is. ve Object.isarasında açıkça ayrım yapar :-0+0

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

15
Gerçekten 1/0 === Infinity; // trueve 1/-0 === -Infinity; // true.
user113716

48
Elimizdeki Yani 1 === 1ve +0 === -0ancak 1/+0 !== 1/-0. Ne kadar tuhaf!
Randomblue

8
@Random: Bence kesinlikle bundan daha iyi +0 !== -0;) Bu gerçekten sorun yaratabilir.
Felix Kling

@FelixKling veya 0 !== +0/ 0 !== -0, gerçekten de sorun yaratacaktır!
Yanick Rochon

5
Aslında, bu davranış modelleri matematikte hesaplamayı sınırlar. Örneğin, işlev 1 / x'in değeri 0'da sonsuzdur, ancak 0'a negatif tarafın pozitifinden yaklaşırsak ayrılır; ilkinde sonuç + inf, ikincisinde -inf'dir.
Agoston Horvath

19

@ User113716 adlı kullanıcının yorumunu göz ardı ettiğim için bunu yanıt olarak ekleyeceğim.

Bunu yaparak -0 için test yapabilirsiniz:

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

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

6
Muhtemelen == 0 değerini de kontrol etmeli, yukarıdaki isMinusZero (-1e-323) doğru döndürür!
Chris

1
@Chris, çift kesinlikli üs sınırı, e±308numaranız sadece denormalize formda temsil edilebilir ve farklı uygulamalar, onları destekleyecekleri veya destekleyecekleri konusunda farklı görüşlere sahiptir. Buradaki nokta, bazı kayan nokta modlarındaki bazı makinelerde -0sayınızın denormalize sayı olarak ve diğerlerinde sayınızdır 0.000000000000001e-308. Bu tür yüzer, çok eğlenceli
poornespase

Bu diğer diller için de işe yarayabilir (C ve bu işler için test yaptım)
Mukul Kumar

11

+0 ve -0'ın gerçekten çok farklı davrandığı bir örnekle karşılaştım:

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

Dikkatli olun: Math.round'u -0.0001 gibi negatif bir sayı üzerinde kullanırken bile, aslında -0 olacaktır ve yukarıda gösterildiği gibi sonraki hesaplamaları bozabilir.

Bunu düzeltmenin hızlı ve kirli yolu, aşağıdaki gibi davranmaktır:

if (x==0) x=0;

ya da sadece:

x+=0;

Bu, -0 olması durumunda sayıyı +0'a dönüştürür.


Teşekkürler. Sıfır eklemenin karşılaştığım problemi nasıl çözeceği çok garip. "Her şey başarısız olursa, sıfır ekleyin." Yaşam için bir ders.
Mikroz

Ben sadece Math.atan (y / x) de karşılaştım, (x şaşırtıcı bir şekilde) olumlu veya olumsuz sonsuz "y / x" işleyebilir, ancak x -0 olduğu durumda yanlış cevap verir. "X" yerine "(x + 0)" kullanılması bunu düzeltir.
Jacob C.

5

In IEEE 754 standardına JavaScript sayısı türü temsil etmek için kullanılır, gösterge bir bit ile temsil edilmektedir (a, 1, negatif bir sayı gösterir).

Sonuç olarak, her bir temsil edilebilir sayı için hem negatif hem de pozitif bir değer vardır; 0 .

Bu yüzden hem -0ve +0sağlıklı olur.


3
Two'nun tamamlayıcısı da işaret için biraz kullanır, ancak sadece bir sıfır (pozitif) vardır.
Felix Kling

1
Evet, ancak Two'nun tamamlayıcısında negatif bit de değerin bir parçasıdır, bu yüzden negatif biti ayarladıktan sonra artık sıfır değildir.
Arnaud Le Blanc

3

Orijinal başlığın cevaplanması Are +0 and -0 the same?:

brainslugs83(yanıtın yorumlarında Spudley) JS'de +0 ve -0'ın aynı olmadığı ve işlev olarak uygulandığı önemli bir duruma dikkat çekti:

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

Bu standart dışında Math.sign+0 ve -0 doğru işaretlerini döndürür.


2

0 için iki olası değer vardır (bit gösterimleri). Bu benzersiz değildir. Özellikle kayan nokta sayılarında bu meydana gelebilir. Çünkü kayan nokta sayıları aslında bir tür formül olarak saklanır.

Tamsayılar ayrı şekillerde de saklanabilir. Ek işaret bitine sahip sayısal bir değere sahip olabilirsiniz, bu nedenle 16 bit alanda 15 bit tam sayı değeri ve işaret biti depolayabilirsiniz. Bu gösterimde, 1000 (hex) ve 0000 değerlerinin her ikisi de 0'dır, ancak bunlardan biri +0 ve diğeri -0'dır.

-1 ile -2 ^ 16 arasında değişen tam sayı değerinden 1 çıkarılarak bu önlenebilir, ancak bu rahatsız edici olacaktır.

Daha yaygın bir yaklaşım, tam sayıları 'iki tamamlayıcıda' saklamaktır, ancak görünüşe göre ECMAscript yapmamayı seçmiştir. Bu yöntemde sayılar 0000 ila 7FFF pozitif arasında değişmektedir. Negatif sayılar FFFF (-1) ile 8000 arasında başlar.

Tabii ki, aynı kurallar daha büyük tamsayılar için de geçerlidir, ancak F'nin yıpranmasını istemiyorum. ;)


4
Ama bunu +0 === -0biraz garip bulmuyorsun . Çünkü şimdi var 1 === 1ve +0 === -0ama 1/+0 !== 1/-0...
Randomblue

2
Tabii ki +0 -0. Her ikisi de hiçbir şey. Ama + sonsuzluk ve-sonsuzluk arasında büyük bir fark var, değil mi? Bu sapma sayıları ECMA'nın hem +0 hem de -1'i desteklemesinin nedeni olabilir.
GolezTrol

+0 === -0İki bit gösteriminin farklı olmasına rağmen nedenini açıklamıyorsunuz .
Randomblue

1
+0 -0, 0, hiçbir şey, nada, niente. Aynı olmaları mantıklı. Gökyüzü neden mavi? Temsiller farklı olmasına rağmen, 4 + 3 de 1 + 6 ile aynıdır. Farklı temsillere (ve dolayısıyla farklı bir bit değerine) sahiptirler, ancak karşılaştırıldığında, oldukları gibi aynı sıfır olarak ele alınırlar.
GolezTrol

1
Aynı değiller . Bunu gösteren örnekler için stackoverflow.com/questions/7223717/differentiating-0-and-0 adresine bakın .
Randomblue

2

Object.is+0 ve -0 ve bir şey daha ayırt etmek için kullanabiliriz NaN==NaN.

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

Object.is(NaN,NaN) //true

1

Sıkı Eşitlik Karşılaştırma yöntemini ('===') suçluyorum. Bölüm 4d'ye bakın resim açıklamasını buraya girin

bakınız 7.2.13 Sıkı Eşitlik Karşılaştırma üzerinde şartname


0

Wikipedia'nın bu fenomeni açıklamak için iyi bir makalesi var: http://en.wikipedia.org/wiki/Signed_zero

Kısacası, hem +0 hem de -0, IEEE kayan nokta özelliklerinde tanımlanmıştır. Her ikisi de teknik olarak bir tamsayı olmayan bir işaret olmadan 0'dan farklıdır, ancak pratikte hepsi sıfıra değerlendirir, bu nedenle ayrım tüm pratik amaçlar için göz ardı edilebilir.


2
Bu tamamen doğru değil - örneğin 1 / -0 == 1/0, javascript'te false olarak değerlendirilir. IEEE
754'te
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.