Ce code:
System.out.println(Math.abs(Integer.MIN_VALUE));
Retour -2147483648
Ne devrait-il pas renvoyer la valeur absolue comme 2147483648
?
java
absolute-value
user665319
la source
la source
Le comportement que vous indiquez est en effet contre-intuitif. Cependant, ce comportement est celui spécifié par le javadoc pour
Math.abs(int)
:Autrement dit,
Math.abs(int)
devrait se comporter comme le code Java suivant:public static int abs(int x){ if (x >= 0) { return x; } return -x; }
Autrement dit, dans le cas négatif,
-x
.Selon la section JLS 15.15.4 , le
-x
est égal à(~x)+1
, où~
est l'opérateur de complément au niveau du bit.Pour vérifier si cela vous convient, prenons -1 comme exemple.
La valeur entière
-1
est peut être notée comme0xFFFFFFFF
en hexadécimal en Java (vérifiez cela avec uneprintln
ou toute autre méthode). Prendre-(-1)
donne ainsi:-(-1) = (~(0xFFFFFFFF)) + 1 = 0x00000000 + 1 = 0x00000001 = 1
Donc, ça marche.
Essayons maintenant avec
Integer.MIN_VALUE
. Sachant que le plus petit entier peut être représenté par0x80000000
, c'est-à-dire le premier bit mis à 1 et les 31 bits restants mis à 0, nous avons:-(Integer.MIN_VALUE) = (~(0x80000000)) + 1 = 0x7FFFFFFF + 1 = 0x80000000 = Integer.MIN_VALUE
Et c'est pourquoi
Math.abs(Integer.MIN_VALUE)
revientInteger.MIN_VALUE
. Notez également que0x7FFFFFFF
c'estInteger.MAX_VALUE
.Cela dit, comment pouvons-nous éviter les problèmes dus à cette valeur de retour contre-intuitive à l'avenir?
Nous pourrions, comme l'a souligné @Bombe , lancer nos
int
slong
avant. Cependant, nous devons soitint
s, ce qui ne fonctionne pas carInteger.MIN_VALUE == (int) Math.abs((long)Integer.MIN_VALUE)
.long
espérant d'une manière ou d'une autre que nous n'appellerons jamaisMath.abs(long)
avec une valeur égale àLong.MIN_VALUE
, puisque nous l'avons également faitMath.abs(Long.MIN_VALUE) == Long.MIN_VALUE
.Nous pouvons utiliser
BigInteger
s partout, carBigInteger.abs()
il renvoie en effet toujours une valeur positive. C'est une bonne alternative, bien qu'un peu plus lente que la manipulation de types entiers bruts.Nous pouvons écrire notre propre wrapper pour
Math.abs(int)
, comme ceci:/** * 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
(débordant essentiellement deInteger.MAX_VALUE
à0
au lieu deInteger.MIN_VALUE
)Pour finir, ce problème semble connu depuis un certain temps. Voir par exemple cette entrée sur la règle findbugs correspondante .
la source
Voici ce que dit Java doc pour Math.abs () dans javadoc :
la source
Pour voir le résultat que vous attendez, effectuez un cast
Integer.MIN_VALUE
enlong
:System.out.println(Math.abs((long) Integer.MIN_VALUE));
la source
Math.abs
est contre-intuitif en renvoyant un nombre négatif:Math.abs(Long.MIN_VALUE) == Long.MIN_VALUE
ArithmeticException
? En outre, le comportement est clairement documenté dans la documentation de l'API.Math.abs(long)
. Je m'excuse de mon erreur ici: j'ai pensé que vous aviez proposé l'utilisation deMath.abs(long)
comme solution, lorsque vous l'avez montré comme un moyen simple de "voir le résultat attendu par le demandeur". Pardon.2147483648 ne peut pas être stocké dans un entier en java, sa représentation binaire est la même que -2147483648.
la source
Mais
(int) 2147483648L == -2147483648
il y a un nombre négatif qui n'a pas d'équivalent positif donc il n'y a pas de valeur positive pour lui. Vous verrez le même comportement avec Long.MAX_VALUE.la source
Il y a un correctif à cela dans Java 15 sera une méthode à int et long. Ils seront présents sur les classes
Les méthodes.
public static int absExact(int a) public static long absExact(long a)
Si vous réussissez
OU
Une exception est lancée.
https://bugs.openjdk.java.net/browse/JDK-8241805
Je voudrais voir si Long.MIN_VALUE ou Integer.MIN_VALUE est passé une valeur positive serait return et non une exception mais
la source
Math.abs ne fonctionne pas tout le temps avec de grands nombres J'utilise cette petite logique de code que j'ai apprise quand j'avais 7 ans!
if(Num < 0){ Num = -(Num); }
la source
s
ici?Num
égalInteger.MIN_VALUE
avant l'extrait de code?