Este código:
System.out.println(Math.abs(Integer.MIN_VALUE));
Devoluciones -2147483648
¿No debería devolver el valor absoluto como 2147483648?
Este código:
System.out.println(Math.abs(Integer.MIN_VALUE));
Devoluciones -2147483648
¿No debería devolver el valor absoluto como 2147483648?
Respuestas:
Integer.MIN_VALUEes -2147483648, pero el valor más alto que puede contener un entero de 32 bits es +2147483647. Intentar representar +2147483648en un int de 32 bits efectivamente "pasará" a -2147483648. Esto se debe a que, al usar enteros con signo, las representaciones binarias en complemento a dos de +2147483648y -2147483648son idénticas. Sin embargo, esto no es un problema, ya que +2147483648se considera fuera de rango.
Para leer un poco más sobre este tema, es posible que desee consultar el artículo de Wikipedia sobre el complemento de dos .
El comportamiento que señala es, de hecho, contrario a la intuición. Sin embargo, este comportamiento es el especificado por el javadoc paraMath.abs(int) :
Si el argumento no es negativo, se devuelve el argumento. Si el argumento es negativo, se devuelve la negación del argumento.
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 , -xes 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 -1se puede anotar como 0xFFFFFFFFen hexadecimal en Java (verifique esto con uno printlno 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 por 0x80000000, 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)vuelve Integer.MIN_VALUE. También tenga en cuenta que 0x7FFFFFFFes Integer.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 ints que longantes. Nosotros, sin embargo, debemos
ints, lo que no funciona porque
Integer.MIN_VALUE == (int) Math.abs((long)Integer.MIN_VALUE).longs de alguna manera esperando que nunca llamemos Math.abs(long)con un valor igual a Long.MIN_VALUE, ya que también lo hemos hecho Math.abs(Long.MIN_VALUE) == Long.MIN_VALUE.Podemos usar BigIntegers en todas partes, porque de BigInteger.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 de Integer.MAX_VALUEa en 0lugar de Integer.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 .
Para ver el resultado que espera, envíe Integer.MIN_VALUEa long:
System.out.println(Math.abs((long) Integer.MIN_VALUE));
Math.absestá 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 de Math.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.
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.
Hay una solución para esto en Java 15 será un método para int y long. Estarán presentes en las clases.
java.lang.Math and java.lang.StrictMath
Los métodos.
public static int absExact(int a)
public static long absExact(long a)
Si pasa
Integer.MIN_VALUE
O
Long.MIN_VALUE
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.
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);
}
saquí?
Numes igual Integer.MIN_VALUEantes del fragmento?