Dieser Code:
System.out.println(Math.abs(Integer.MIN_VALUE));
Kehrt zurück -2147483648
Sollte es nicht den absoluten Wert als zurückgeben 2147483648
?
Dieser Code:
System.out.println(Math.abs(Integer.MIN_VALUE));
Kehrt zurück -2147483648
Sollte es nicht den absoluten Wert als zurückgeben 2147483648
?
Antworten:
Integer.MIN_VALUE
ist -2147483648
, aber der höchste Wert, den eine 32-Bit-Ganzzahl enthalten kann, ist +2147483647
. Der Versuch, +2147483648
in einem 32-Bit-Int darzustellen, wird effektiv auf "rollen" -2147483648
. Dies liegt daran, dass bei Verwendung vorzeichenbehafteter Ganzzahlen die beiden komplementären binären Darstellungen von +2147483648
und -2147483648
identisch sind. Dies ist jedoch kein Problem, da dies +2147483648
als außerhalb des Bereichs liegend angesehen wird.
Wenn Sie mehr darüber lesen möchten, lesen Sie vielleicht den Wikipedia-Artikel über die Ergänzung von Two .
Das Verhalten, auf das Sie hinweisen, ist in der Tat kontraintuitiv. Dieses Verhalten ist jedoch das vom Javadoc angegebene fürMath.abs(int)
:
Wenn das Argument nicht negativ ist, wird das Argument zurückgegeben. Wenn das Argument negativ ist, wird die Negation des Arguments zurückgegeben.
Das heißt, Math.abs(int)
sollte sich wie der folgende Java-Code verhalten:
public static int abs(int x){
if (x >= 0) {
return x;
}
return -x;
}
Das heißt, im negativen Fall -x
.
Gemäß dem JLS-Abschnitt 15.15.4 ist das -x
gleich (~x)+1
, wobei ~
der bitweise Komplementoperator ist.
Um zu überprüfen, ob dies richtig klingt, nehmen wir als Beispiel -1.
Der ganzzahlige Wert -1
kann 0xFFFFFFFF
in Java wie hexadezimal angegeben werden (überprüfen Sie dies mit einer println
oder einer anderen Methode). Nehmen -(-1)
gibt also:
-(-1) = (~(0xFFFFFFFF)) + 1 = 0x00000000 + 1 = 0x00000001 = 1
Also funktioniert es.
Versuchen wir es jetzt mit Integer.MIN_VALUE
. In dem Wissen, dass die niedrigste Ganzzahl durch 0x80000000
das erste auf 1 gesetzte Bit und die 31 verbleibenden auf 0 gesetzten Bits dargestellt werden kann, haben wir:
-(Integer.MIN_VALUE) = (~(0x80000000)) + 1 = 0x7FFFFFFF + 1
= 0x80000000 = Integer.MIN_VALUE
Und deshalb Math.abs(Integer.MIN_VALUE)
kehrt zurück Integer.MIN_VALUE
. Beachten Sie auch , dass 0x7FFFFFFF
ist Integer.MAX_VALUE
.
Wie können wir jedoch in Zukunft Probleme aufgrund dieses kontraintuitiven Rückgabewerts vermeiden?
Wir könnten, wie von @Bombe betont , unsere int
s long
vorher besetzen . Wir müssen jedoch auch
int
s, was da nicht funktioniert
Integer.MIN_VALUE == (int) Math.abs((long)Integer.MIN_VALUE)
.long
s fort und hoffen Sie irgendwie, dass wir niemals Math.abs(long)
mit einem Wert gleich anrufen Long.MIN_VALUE
, da wir auch haben Math.abs(Long.MIN_VALUE) == Long.MIN_VALUE
.Wir können BigInteger
s überall verwenden, weil BigInteger.abs()
es in der Tat immer einen positiven Wert zurückgibt. Dies ist eine gute Alternative, wenn auch etwas langsamer als das Bearbeiten von rohen Ganzzahltypen.
Wir können unseren eigenen Wrapper für Folgendes schreiben Math.abs(int)
:
/**
* Fail-fast wrapper for {@link Math#abs(int)}
* @param x
* @return the absolute value of x
* @throws ArithmeticException when a negative value would have been returned by {@link Math#abs(int)}
*/
public static int abs(int x) throws ArithmeticException {
if (x == Integer.MIN_VALUE) {
// fail instead of returning Integer.MAX_VALUE
// to prevent the occurrence of incorrect results in later computations
throw new ArithmeticException("Math.abs(Integer.MIN_VALUE)");
}
return Math.abs(x);
}
int positive = value & Integer.MAX_VALUE
(im Wesentlichen überlaufend von Integer.MAX_VALUE
nach 0
statt statt Integer.MIN_VALUE
)Abschließend scheint dieses Problem seit einiger Zeit bekannt zu sein. Siehe zum Beispiel diesen Eintrag über die entsprechende Findbugs-Regel .
Um das erwartete Ergebnis zu sehen, gehen Sie wie folgt Integer.MIN_VALUE
vor long
:
System.out.println(Math.abs((long) Integer.MIN_VALUE));
Math.abs
es nicht Math.abs(Long.MIN_VALUE) == Long.MIN_VALUE
ArithmeticException
? Das Verhalten ist auch in der API-Dokumentation klar dokumentiert.
Math.abs(long)
. Ich entschuldige mich für meinen Fehler hier: Ich habe gedacht, dass Sie die Verwendung Math.abs(long)
als Fix vorgeschlagen haben, als Sie es als einfache Möglichkeit gezeigt haben, "das Ergebnis zu sehen, das der Fragesteller erwartet". Es tut uns leid.
Es (int) 2147483648L == -2147483648
gibt jedoch eine negative Zahl, die kein positives Äquivalent hat, sodass es keinen positiven Wert dafür gibt. Sie werden das gleiche Verhalten mit Long.MAX_VALUE sehen.
Es gibt eine Lösung dafür in Java 15 wird eine Methode zu int und long sein. Sie werden in den Klassen anwesend sein
java.lang.Math and java.lang.StrictMath
Die Methoden.
public static int absExact(int a)
public static long absExact(long a)
Wenn Sie bestehen
Integer.MIN_VALUE
ODER
Long.MIN_VALUE
Eine Ausnahme wird ausgelöst.
https://bugs.openjdk.java.net/browse/JDK-8241805
Ich würde gerne sehen, ob entweder Long.MIN_VALUE oder Integer.MIN_VALUE übergeben wird. Ein positiver Wert wäre return und keine Ausnahme, aber.
Math.abs funktioniert nicht immer mit großen Zahlen. Ich verwende diese kleine Codelogik, die ich mit 7 Jahren gelernt habe!
if(Num < 0){
Num = -(Num);
}
s
hier
Num
equals Integer.MIN_VALUE
vor dem Snippet?