Este código:
System.out.println(Math.abs(Integer.MIN_VALUE));
Devoluciones -2147483648
¿No debería devolver el valor absoluto como 2147483648
?
java
absolute-value
usuario665319
fuente
fuente
El comportamiento que señala es, de hecho, contrario a la intuición. Sin embargo, este comportamiento es el especificado por el javadoc para
Math.abs(int)
:Es decir,
Math.abs(int)
debería comportarse como el siguiente código Java:public static int abs(int x){ if (x >= 0) { return x; } return -x; }
Es decir, en caso negativo,
-x
.De acuerdo con la sección 15.15.4 de JLS ,
-x
es igual a(~x)+1
, donde~
es el operador de complemento a nivel de bits.Para comprobar si esto suena bien, tomemos -1 como ejemplo.
El valor entero
-1
se puede anotar como0xFFFFFFFF
en hexadecimal en Java (verifique esto con unoprintln
o cualquier otro método). Tomando-(-1)
así da:-(-1) = (~(0xFFFFFFFF)) + 1 = 0x00000000 + 1 = 0x00000001 = 1
Entonces funciona.
Probemos ahora con
Integer.MIN_VALUE
. Sabiendo que el entero más bajo puede ser representado por0x80000000
, es decir, el primer bit puesto a 1 y los 31 bits restantes puestos a 0, tenemos:-(Integer.MIN_VALUE) = (~(0x80000000)) + 1 = 0x7FFFFFFF + 1 = 0x80000000 = Integer.MIN_VALUE
Y es por eso que
Math.abs(Integer.MIN_VALUE)
vuelveInteger.MIN_VALUE
. También tenga en cuenta que0x7FFFFFFF
esInteger.MAX_VALUE
.Dicho esto, ¿cómo podemos evitar problemas debido a este valor de retorno contraintuitivo en el futuro?
Podríamos, como salir en punta por @Bombe , echar las
int
s quelong
antes. Nosotros, sin embargo, debemosint
s, lo que no funciona porqueInteger.MIN_VALUE == (int) Math.abs((long)Integer.MIN_VALUE)
.long
s de alguna manera esperando que nunca llamemosMath.abs(long)
con un valor igual aLong.MIN_VALUE
, ya que también lo hemos hechoMath.abs(Long.MIN_VALUE) == Long.MIN_VALUE
.Podemos usar
BigInteger
s en todas partes, porque deBigInteger.abs()
hecho siempre devuelve un valor positivo. Esta es una buena alternativa, aunque un poco más lenta que manipular tipos enteros sin procesar.Podemos escribir nuestro propio contenedor para
Math.abs(int)
, así:/** * 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
(esencialmente desbordando deInteger.MAX_VALUE
a en0
lugar deInteger.MIN_VALUE
)Como nota final, este problema parece conocerse desde hace algún tiempo. Vea, por ejemplo, esta entrada sobre la regla correspondiente de findbugs .
fuente
Esto es lo que dice Java doc para Math.abs () en javadoc :
fuente
Para ver el resultado que espera, envíe
Integer.MIN_VALUE
along
:System.out.println(Math.abs((long) Integer.MIN_VALUE));
fuente
Math.abs
está siendo contradictorio al devolver un número negativo:Math.abs(Long.MIN_VALUE) == Long.MIN_VALUE
ArithmeticException
? Además, el comportamiento está claramente documentado en la documentación de la API.Math.abs(long)
. Pido disculpas por mi error aquí: pensé que propusiste el uso deMath.abs(long)
como solución, cuando lo mostraste como una forma sencilla de "ver el resultado que espera el autor de la pregunta". Lo siento.2147483648 no se puede almacenar en un número entero en Java, su representación binaria es la misma que -2147483648.
fuente
Pero
(int) 2147483648L == -2147483648
hay un número negativo que no tiene equivalente positivo, por lo que no tiene un valor positivo. Verá el mismo comportamiento con Long.MAX_VALUE.fuente
Hay una solución para esto en Java 15 será un método para int y long. Estarán presentes en las clases.
Los métodos.
public static int absExact(int a) public static long absExact(long a)
Si pasa
O
Se lanza una excepción.
https://bugs.openjdk.java.net/browse/JDK-8241805
Me gustaría ver si se pasa Long.MIN_VALUE o Integer.MIN_VALUE, se devolvería un valor positivo y no una excepción, pero.
fuente
Math.abs no funciona todo el tiempo con números grandes. ¡Utilizo esta pequeña lógica de código que aprendí cuando tenía 7 años!
if(Num < 0){ Num = -(Num); }
fuente
s
aquí?Num
es igualInteger.MIN_VALUE
antes del fragmento?