Pregunta

Este código:

System.out.println(Math.abs(Integer.MIN_VALUE));

Devoluciones -2147483648

¿No debería devolver el valor absoluto como 2147483648 ?

¿Fue útil?

Solución

Integer.MIN_VALUE es -2147483648, pero el valor más alto que puede contener un entero de 32 bits es +2147483647.Intentando representar +2147483648 en un int de 32 bits efectivamente se "pasará" a -2147483648.Esto se debe a que, cuando se utilizan números enteros con signo, las representaciones binarias en complemento a dos de +2147483648 y -2147483648 Son identicos.Sin embargo, esto no es un problema, ya que +2147483648 se 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 a dos.

Otros consejos

El comportamiento que usted señala es, de hecho, contrario a la intuición.Sin embargo, este comportamiento es el especificado por el javadoc para Math.abs(int):

Si el argumento no es negativo, se devuelve el argumento.Si el argumento es negativo, se devuelve la negación del argumento.

Eso es, 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 el caso negativo, -x.

De acuerdo con la JLS sección 15.15.4, el -x es igual a (~x)+1, dónde ~ es el operador de complemento bit a bit.

Para comprobar si esto suena bien, tomemos -1 como ejemplo.

El valor entero -1 Esto se puede notar como 0xFFFFFFFF en hexadecimal en Java (mira esto con un println o cualquier otro método).Tomando -(-1) así da:

-(-1) = (~(0xFFFFFFFF)) + 1 = 0x00000000 + 1 = 0x00000001 = 1

Entonces funciona.

Intentemos ahora con Integer.MIN_VALUE .Sabiendo que el número entero más bajo se puede representar 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 esto Math.abs(Integer.MIN_VALUE) devoluciones Integer.MIN_VALUE.También tenga en cuenta que 0x7FFFFFFF es Integer.MAX_VALUE.

Dicho esto, ¿cómo podemos evitar problemas debido a este valor de retorno contrario a la intuición en el futuro?

  • Pudimos, como lo señala @Bombe, emitir nuestro ints a long antes.Nosotros, sin embargo, debemos

    • arrojarlos de nuevo a ints, lo cual no funciona porqueInteger.MIN_VALUE == (int) Math.abs((long)Integer.MIN_VALUE).
    • O continuar con longDe alguna manera tengo la esperanza de que nunca llamemos Math.abs(long) con un valor igual a Long.MIN_VALUE, ya que también tenemos Math.abs(Long.MIN_VALUE) == Long.MIN_VALUE.
  • Nosotros podemos usar BigIntegerestá en todas partes, porque BigInteger.abs() De hecho, siempre devuelve un valor positivo.Esta es una buena alternativa, aunque un poco más lenta que manipular tipos enteros sin formato.

  • Podemos escribir nuestro propio envoltorio para Math.abs(int), como esto:

/**
 * 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);
}
  • Utilice un número entero bit a bit Y para borrar el bit alto, asegurándose de que el resultado no sea negativo: int positive = value & Integer.MAX_VALUE (esencialmente desbordante de Integer.MAX_VALUE a 0 en lugar de Integer.MIN_VALUE)

Como nota final, este problema parece ser conocido desde hace algún tiempo.ver por ejemplo esta entrada sobre la regla findbugs correspondiente.

Aquí está lo que dice Java Doc para math.abs () en javadoc :

Tenga en cuenta que si el argumento es igual a el valor del entero.min_value, el El valor INT más representable negativo, El resultado es ese mismo valor, que es negativo.

Para ver el resultado que esperas, lanza Integer.MIN_VALUE a long:

System.out.println(Math.abs((long) Integer.MIN_VALUE));

2147483648 no se puede almacenar en un entero en Java, su representación binaria es la misma que -2147483648.

pero (int) 2147483648L == -2147483648 Hay un número negativo que no tiene un equivalente positivo, por lo que no hay un valor positivo para ello.Verá el mismo comportamiento con Long.max_Value.

math.abs no funciona todo el tiempo con grandes números ¡Utilizo esta lógica de códigos que aprendí cuando tenía 7 años!

if(Num < 0){
  Num = -(s);
} 

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top