Wie überprüfe ich, ob eine Null positiv oder negativ ist?

75

Kann überprüft werden, ob a floateine positive Null (0,0) oder eine negative Null (-0,0) ist?

Ich habe das floatin ein konvertiert Stringund überprüft, ob das erste ein charist '-', aber gibt es andere Möglichkeiten?

e4lime
quelle
8
Das Überprüfen des Vorzeichenbits (Bit ganz links) sollte ausreichen
boxed__l
6
In der Tat ist Null weder eine negative noch eine positive Zahl.
Grijesh Chauhan
21
@GrijeshChauhan: Nur theoretisch
Mooing Duck
10
@fridge: aber die Frage ist nicht über Mathematik, es geht um Java. Jede Beziehung, die Gleitkommawerte zu Zahlen haben könnten, ist menschliches Design und neigt zu undichten Abstraktionen ;-)
Steve Jessop
3
Mag eine dumme Frage sein, aber ich habe mich nur gefragt: Warum muss man zwischen einer positiven und einer negativen 0 unterscheiden?
Siegi

Antworten:

80

Ja, teile es. 1 / +0.0fist +Infinity, aber 1 / -0.0fist -Infinity. Mit einem einfachen Vergleich können Sie leicht herausfinden, um welches es sich handelt. Sie erhalten also:

if (1 / x > 0)
    // +0 here
else
    // -0 here

(Dies setzt voraus, dass xnur eine der beiden Nullen sein kann)

Harold
quelle
6
Wäre es nicht einfacher, das Vorzeichen der Null mit Math.copySign auf eine andere Zahl, z. B. 1.0, zu übertragen? ZBif (math.copySign (1.0, x) < 0.0) ...
Njuffa
3
@njuffa: Nicht sicher, wie math.copySign(1.0,x)<0.0"einfacher" ist als 1/x>0. Ich meine, beide sind ziemlich selbsterklärend, also möchten Sie sowieso eine Funktion dafür haben
Niklas B.
2
@njuffa: Ja, ich dachte, Sie Probleme mit der Lesbarkeit mit dieser Antwort;) Ich habe nicht gedacht, dass die Teilung schwer sein würde, da es wahrscheinlich sowieso einen Sonderfall für Nullteiler gibt
Niklas B.
1
Nun, wenn ihr wissen wollt, wie schwer es ist, dann kommt es darauf an. Zum Beispiel ist eine Zeichenübertragung mit x87-Anweisungen ärgerlich, aber mit SSE großartig. Und wie lange die Teilung dauert, reicht von 9 (glaube ich?) Bis zu über hundert Zyklen (abhängig von den zu teilenden Werten und dem µarch). Entweder könnte man gewinnen, und das ist nur auf x86-Systemen.
Harold
1
Wenn Sie nur Effizienz wollen, wäre es dann nicht die beste Lösung, sie in ein int umzuwandeln und das Vorzeichenbit abzufragen? Ich bin mir nicht sicher, wie effizient Sie dies in Java tun können, aber auf den meisten Architekturen kann dies einfach mit einem ODER-Befehl gefolgt von einem Sprung-Null- oder Sprung-Nicht-Null-Befehl erfolgen, und der OP ist normalerweise ein Zyklus. Die bedingten Sprungkosten variieren jedoch stark je nach Architektur.
Reirab
39

Sie können Float.floatToIntBitses in ein konvertieren intund das Bitmuster betrachten:

float f = -0.0f;

if (Float.floatToIntBits(f) == 0x80000000) {
    System.out.println("Negative zero");
}
Jesper
quelle
Viel besser als das Teilen, was mehrere Taktzyklen dauern und einen Überlaufzustand in der FPU-Einheit einfangen kann. Besser noch:(Float.floatToIntBits(f) & 0x80000000) < 0
Mark Jeronimus
12

Auf jeden Fall nicht der beste Ansatz. Überprüfen Sie die Funktion

Float.floatToRawIntBits(f);

Doku:

/**
 * Returns a representation of the specified floating-point value
 * according to the IEEE 754 floating-point "single format" bit
 * layout, preserving Not-a-Number (NaN) values.
 *
 * <p>Bit 31 (the bit that is selected by the mask
 * {@code 0x80000000}) represents the sign of the floating-point
 * number.
 ...
 public static native int floatToRawIntBits(float value);
andre baresel
quelle
10

Double.equalsunterscheidet ± 0,0 in Java. (Es gibt auch Float.equals.)

Ich bin ein bisschen überrascht, dass niemand diese erwähnt hat, da sie mir klarer erscheinen als jede bisher angegebene Methode!

Reuben Thomas
quelle
Das ist in der Tat klarer; Möglicherweise möchten Sie jedoch nicht zwei Objekte auf dem Heap zuweisen, um nur zwei Werte zu vergleichen.
Klitos Kyriacou
7

Der von verwendete Ansatz Math.minähnelt dem, was Jesper vorschlägt, ist jedoch etwas klarer:

private static int negativeZeroFloatBits = Float.floatToRawIntBits(-0.0f);

float f = -0.0f;
boolean isNegativeZero = (Float.floatToRawIntBits(f) == negativeZeroFloatBits);
Assylien
quelle
6

Wenn ein Float negativ ist (einschließlich -0.0und -inf), verwendet er dasselbe Vorzeichenbit wie ein negatives int. Dies bedeutet, dass Sie die Ganzzahldarstellung mit vergleichen können 0, sodass Sie die Ganzzahldarstellung nicht kennen oder berechnen müssen von -0.0:

if(f == 0.0) {
  if(Float.floatToIntBits(f) < 0) {
    //negative zero
  } else {
    //positive zero
  }
}

Das hat einen zusätzlichen Zweig über der akzeptierten Antwort, aber ich denke, es ist besser lesbar ohne eine Hex-Konstante.

Wenn Ihr Ziel nur darin besteht, -0 als negative Zahl zu behandeln, können Sie die äußere ifAussage weglassen:

if(Float.floatToIntBits(f) < 0) {
  //any negative float, including -0.0 and -inf
} else {
  //any non-negative float, including +0.0, +inf, and NaN
}
Pennen
quelle
0

Für negativ:

new Double(-0.0).equals(new Double(value));

Für positiv:

new Double(0.0).equals(new Double(value));
Tridib
quelle