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_VALUEist -2147483648, aber der höchste Wert, den eine 32-Bit-Ganzzahl enthalten kann, ist +2147483647. Der Versuch, +2147483648in 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 +2147483648und -2147483648identisch sind. Dies ist jedoch kein Problem, da dies +2147483648als 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 -xgleich (~x)+1, wobei ~der bitweise Komplementoperator ist.
Um zu überprüfen, ob dies richtig klingt, nehmen wir als Beispiel -1.
Der ganzzahlige Wert -1kann 0xFFFFFFFFin Java wie hexadezimal angegeben werden (überprüfen Sie dies mit einer printlnoder 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 0x80000000das 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 0x7FFFFFFFist 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 ints longvorher besetzen . Wir müssen jedoch auch
ints, was da nicht funktioniert
Integer.MIN_VALUE == (int) Math.abs((long)Integer.MIN_VALUE).longs 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 BigIntegers ü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_VALUEnach 0statt 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_VALUEvor long:
System.out.println(Math.abs((long) Integer.MIN_VALUE));
Math.abses 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);
}
shier
Numequals Integer.MIN_VALUEvor dem Snippet?