+0 ve -0, int ve float verileri için farklı davranışlar gösterir


16

Bu yazıyı negatif ve pozitif sıfır okudum .

Benim anlayışım için aşağıdaki kod vermeli true ve true çıktı olarak.

Ancak, veriyor falseve truebir çıktı olarak.

Negatif sıfırı pozitif sıfıyla karşılaştırıyorum.

public class Test {
     public static void main(String[] args) {
            float f = 0;
            float f2 = -f;
            Float F = new Float(f);
            Float F1 = new Float(f2);
            System.out.println(F1.equals(F));

            int i = 0;
            int i2 = -i;
            Integer I = new Integer(i);
            Integer I1 = new Integer(i2);
            System.out.println(I1.equals(I));
      }
  }

Neden 0'lar için Integerve için farklı davranışlarımız var Float?


11
Javadocs'u kontrol ederseniz, docs.oracle.com/javase/8/docs/api/java/lang/… Tanım, karma tabloların düzgün çalışmasını sağlar. Ayrıca, -0 tamsayısı yoktur.
matt

@matt -0 tamsayı değilse yanlış olarak değerlendirilmelidir ...
Joker

3
İ2 = -i; i2, i'nin tam bit temsilini alır, onları ayırt etmenin bir yolu yoktur. ive i2tamamen aynı. Sonra yeni Integers oluşturduğunuzda, her ikisi de aynı değeri sarar. I1.equals(I)doğru olacak.
matt

1
Deneyin int i = Integer.MIN_VALUE, i2 = -i;
Holger

1
Bu arada, newburada sargı tipleri için kullanmak için bir neden yoktur . Sadece kullanın, örneğinInteger i = 0, i2 = -i; System.out.println(i.equals(i2)); Float f1 = 0f, f2 = -f1; System.out.println(f1.equals(f2));
Holger

Yanıtlar:


19

Ints ve şamandıralar Java'da oldukça farklı hayvanlardır. Ints, tek bir 0 değerine sahip ikinin tamamlayıcısı olarak kodlanır . Şamandıralar IEEE 754'ü ( şamandıralar için 32 bit , çiftler için 64 bit ) kullanır. IEEE 754 biraz karmaşıktır, ancak bu cevabın amacı için, birincisi bir işaret biti olan üç bölüme sahip olduğunu bilmeniz gerekir. Bu, herhangi bir şamandıra için olumlu ve olumsuz bir varyant olduğu anlamına gelir¹. Bu 0 içerir, bu nedenle şamandıralar aslında iki "sıfır" değere sahiptir, +0 ve -0.

Bir kenara, ikisinin ints kullanımı tamamlayıcısı bilgisayar biliminde tamsayıları kodlamanın tek yolu değildir. Bunların tamamlayıcısı gibi başka yöntemler de vardır , ancak tuhaflıkları vardır - hem +0 hem de -0'ın farklı değerler olarak olması gibi. ;-)

Şamandıra ilkellerini (ve çiftler) karşılaştırdığınızda, Java +0 ve -0'a eşit davranır. Ancak bunları işaretlediğinizde, Java bunları açıklandığı gibi ayrı ayrı ele alır Float#equals. Bu, eşittir yönteminin , yalnızca şamandıranın bitlerini (işaretli değer dahil) kullanan ve bunları int hashCodeolarak olduğu gibi uygulayan uygulamalarıyla tutarlı olmasına izin verir compareTo.

Equals / hashCode / comparTo için başka bir seçenek seçmiş olabilirlerdi, ama etmediler. Tasarım düşüncelerinin ne olduğundan emin değilim. Fakat en azından bir açıdan, Float#equalsher zaman şamandıra ilkelinden sapacaktı ==: İlkellerde NaN != NaN, ancak tüm nesneler için o.equals(o)de doğru olmalı . Bu, eğer olsaydı Float f = Float.NaN, o zaman f.equals(f)bile f.floatValue() != f.floatValue().


¹ NaN (sayı olmayan) değerlerin işaret biti vardır, ancak sipariş vermenin dışında bir anlamı yoktur ve Java bunu yok sayar (sipariş için bile).


10

Bu Float eşit istisna biridir

iki istisna vardır:

F1 + 0.0f'yi temsil ederken f2 -0.0f'yi temsil ediyorsa veya tam tersi ise, eşit test yanlış değerine sahiptir

Neden ayrıca açıklanmaktadır:

Bu tanım hash tablolarının düzgün çalışmasına izin verir.

-0 ve 0, Float'ın 31 biti kullanılarak farklı şekilde temsil edilecektir:

Bit 31 (maske 0x80000000 tarafından seçilen bit) kayan nokta sayısının işaretini temsil eder.

Durum böyle değil Integer


soru neden? Tıkmak zorunda olduğumuz bu zor ve hızlı kural :(
Joker

@Joker Alıntı eklendi karma tabloların düzgün çalışmasına izin verir
user7294900

4
Bu cevabın (ve javadocun) bahsetmediği önemli bir parça, farkın şamandıralarda, +0 ve -0'ın farklı değerler - eşdeğer ama farklı olmasıdır. Temel olarak, şamandıraların üç kısmı vardır ve ilk kısım, şamandıranın pozitif mi negatif mi olduğunu söyleyen tek bir bittir. Budur değil sadece tek bir 0 değerine sahip (Java temsil gibi) ints kılıfı.
yshavit

@yshavit Teşekkürler, lütfen aynı cevapla paylaşır mısınız
Joker

3
@Joker Bit 31 (0x80000000 maskesi tarafından seçilen bit) kayan nokta sayısının işaretini temsil eder.
user7294900

5

Tam sayılar için, tam sayılar için -0 ile 0 arasında bir ayrım yoktur, çünkü Twos iltifat gösterimini kullanır . Yani tamsayı örneğiniz ive i1tam olarak aynı.

Şamandıralar için -0 gösterimi vardır ve değeri 0'a eşittir, ancak bit gösterimi farklıdır. Dolayısıyla yeni Şamandıra (0f) ve yeni Şamandıra (-0f) farklı temsillere sahip olacaktır.

Bit gösterimlerindeki farkı görebilirsiniz.

System.out.println(Float.floatToIntBits(-0f) + ", " + Float.floatToIntBits(0f));

-2147483648, 0

Ve eğer fbildirmek için bırakırsanız , -0fo zaman bir tamsayı olarak kabul edilir ve çıktıda herhangi bir fark görmezsiniz.


Yine de ilkel şamandıra bununla iyi çalışıyor gibi görünüyor. Öyle 0.0f == -0.0f. Yani farklı davranış sadece içinde java.lang.Float.
ivant

3
@ivant IEEE754 göre, "normal karşılaştırma işlemleri, bununla birlikte, tedavi sıralanmamış olarak NaN'ler düşük -0 ve eşit + 0" en.m.wikipedia.org/wiki/IEEE_754
Andy Turner

@AndyTurner, evet bunu anlıyorum. Sadece Java'da floatbu konuda IEEE754 ile uyumlu olan ve olmayan ilkel tip arasındaki davranışta bir fark olduğunu belirtiyorum java.lang.Float. Bu yüzden, sadece bit gösterimindeki fark bunu açıklamak için yeterli değildir.
ivant
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.