Este código:
System.out.println(Math.abs(Integer.MIN_VALUE));
Devoluções -2147483648
Não deveria retornar o valor absoluto como 2147483648
?
java
absolute-value
user665319
fonte
fonte
O comportamento que você aponta é, de fato, contra-intuitivo. No entanto, esse comportamento é o especificado pelo javadoc para
Math.abs(int)
:Ou seja,
Math.abs(int)
deve se comportar como o seguinte código Java:public static int abs(int x){ if (x >= 0) { return x; } return -x; }
Ou seja, em caso negativo
-x
,.De acordo com a seção 15.15.4 do JLS ,
-x
é igual a(~x)+1
, onde~
é o operador de complemento bit a bit.Para verificar se isso está certo, vamos pegar -1 como exemplo.
O valor inteiro
-1
pode ser anotado como0xFFFFFFFF
em hexadecimal em Java (verifique isso com umprintln
ou qualquer outro método). Tomando-(-1)
assim dá:-(-1) = (~(0xFFFFFFFF)) + 1 = 0x00000000 + 1 = 0x00000001 = 1
Então, funciona.
Vamos tentar agora com
Integer.MIN_VALUE
. Sabendo que o menor inteiro pode ser representado por0x80000000
, ou seja, o primeiro bit definido como 1 e os 31 bits restantes definidos como 0, temos:-(Integer.MIN_VALUE) = (~(0x80000000)) + 1 = 0x7FFFFFFF + 1 = 0x80000000 = Integer.MIN_VALUE
E é por isso que
Math.abs(Integer.MIN_VALUE)
retornaInteger.MIN_VALUE
. Observe também que0x7FFFFFFF
éInteger.MAX_VALUE
.Dito isso, como podemos evitar problemas devido a esse valor de retorno contra-intuitivo no futuro?
Poderíamos, como apontado por @Bombe , lançar nossos
int
s paralong
antes. Nós, no entanto, devemosint
s, o que não funciona porqueInteger.MIN_VALUE == (int) Math.abs((long)Integer.MIN_VALUE)
.long
s, de alguma forma, esperando que nunca paguemosMath.abs(long)
com um valor igual aLong.MIN_VALUE
, já que também fizemosMath.abs(Long.MIN_VALUE) == Long.MIN_VALUE
.Podemos usar
BigInteger
s em qualquer lugar, porque deBigInteger.abs()
fato sempre retorna um valor positivo. Esta é uma boa alternativa, embora um pouco mais lenta do que manipular tipos inteiros brutos.Podemos escrever nosso próprio wrapper para
Math.abs(int)
, assim:/** * 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
(essencialmente transbordando deInteger.MAX_VALUE
para em0
vez deInteger.MIN_VALUE
)Como nota final, este problema parece ser conhecido há algum tempo. Veja, por exemplo, esta entrada sobre a regra de findbugs correspondente .
fonte
Aqui está o que o documento Java diz para Math.abs () em javadoc :
fonte
Para ver o resultado que você espera, lance
Integer.MIN_VALUE
paralong
:System.out.println(Math.abs((long) Integer.MIN_VALUE));
fonte
Math.abs
está sendo contra-intuitivo ao retornar um número negativo:Math.abs(Long.MIN_VALUE) == Long.MIN_VALUE
ArithmeticException
? Além disso, o comportamento está claramente documentado na documentação da API.Math.abs(long)
. Peço desculpas pelo meu erro aqui: achei que você propôs o uso deMath.abs(long)
como uma correção, quando o mostrou como uma forma simples de "ver o resultado que o autor da pergunta está esperando". Desculpe.2147483648 não pode ser armazenado em um inteiro em java, sua representação binária é igual a -2147483648.
fonte
Mas
(int) 2147483648L == -2147483648
há um número negativo que não possui equivalente positivo, portanto não há valor positivo para ele. Você verá o mesmo comportamento com Long.MAX_VALUE.fonte
Existe uma correção para isso em Java 15 será um método para int e long. Eles estarão presentes nas aulas
Os métodos.
public static int absExact(int a) public static long absExact(long a)
Se você passar
OU
Uma exceção é lançada.
https://bugs.openjdk.java.net/browse/JDK-8241805
Gostaria de ver se Long.MIN_VALUE ou Integer.MIN_VALUE é passado, um valor positivo seria return e não uma exceção, mas.
fonte
Math.abs não funciona o tempo todo com números grandes. Eu uso essa pequena lógica de código que aprendi quando tinha 7 anos!
if(Num < 0){ Num = -(Num); }
fonte
s
aqui?Num
igualInteger.MIN_VALUE
antes do snippet?