Bug em Number ou BigInteger e BigDecimal (ou alternativamente na documentação da API deles)?

StackOverflow https://stackoverflow.com/questions/4204133

  •  25-09-2019
  •  | 
  •  

Pergunta

De acordo com a especificação de Number.longValue() o método deve...

Retorna o valor do número especificado como um comprimento.Isso pode envolver arredondamento ou truncamento.

No entanto, o BigInteger (e BigDecimal) substitui esse método e retorna os 64 bits inferiores da parte inteira do número que ele representa.Dos documentos de BigInteger por exemplo:

[...]se este BigInteger for muito grande para caber em um longo, apenas os 64 bits de ordem inferior serão retornados.[...]

Eu afirmo que também "Isso pode envolver arredondamento ou truncamento."não diz qualquer coisa sobre o que o método realmente deve return ou há um bug na implementação ou na documentação.

Você concorda ou cometi um erro no meu raciocínio?


Código de exemplo:

import java.math.BigInteger;
import static java.math.BigInteger.*;

public class Main {
    public static void main(String[] args) {

        BigInteger i = valueOf(Long.MAX_VALUE);

        // Result: Long.MAX_VALUE, just as expected.
        Number n1 = i;
        System.out.println(n1 + " -> " + n1.longValue());

        // I expect to get the "rounded" value Long.MAX_VALUE
        Number n2 = i.add(ONE);
        System.out.println(n2 + " -> " + n2.longValue());

        // I expect to get the "rounded" value Long.MAX_VALUE
        Number n3 = i.multiply(TEN);
        System.out.println(n3 + " -> " + n3.longValue());
    }
}

Saída:

9223372036854775807 -> 9223372036854775807
9223372036854775808 -> -9223372036854775808
92233720368547758070 -> -10
Foi útil?

Solução

A redação "Isso pode envolver arredondamento ou truncamento" aparece nos javadocs para o longValue(), shortValue(), charValue() e byteValue() de Number, então está claro que o "truncamento" se destina a incluir perda de significativo ordem superior bits em alguns casos.

O problema realmente é que o termo "truncamento" significa convencionalmente perda de bits de ordem inferior.(É assim que me lembro do meu curso de análise numérica, há 30 anos.E Wikipédia concorda.)

Em contrapartida, o JLS 5.1.3 descreve o mesmo processo (ao restringir tipos primitivos integrais) da seguinte forma:

Uma conversão restritiva de um inteiro com sinal para um tipo integral T simplesmente descarta todos, exceto os n bits de ordem mais baixa, onde n é o número de bits usados ​​para representar o tipo T.

Então, sim, concordo que o javadoc está incorreto.Envie um relatório de bug.

OBSERVAÇÃO

Eu excluí isso originalmente porque pensei que minha sugestão de enviar um relatório de bug era provavelmente fútil (com base em minha experiência anterior com relatórios de bugs de documentação).Mas @aioobe tem enviou um relatório de bug ...(ID do erro: 7000825)

Outras dicas

A documentação de BigInteger.longValue() continua com:

Observe que essa conversão pode perder informações sobre a magnitude geral do valor de Biginteger, bem como como devolver um resultado com o sinal oposto.

Isso redefine (ou esclarece) o comportamento definido por Number.longValue(). Isso é bom, embora às vezes seja enganoso. Por exemplo java.util.Set redefine o comportamento do add método (por restringindo duplicatas). Se você passar um Collection Você pode esperar que ele mantenha quaisquer valores, mas a implementação concreta redefiniu esse comportamento.

Atualizar: Eu verifiquei como Long.valueOf(Long.MAX_VALUE).intValue() se comporta. E imprime -1. Então, eu suponho que por "redondo ou truncado" é apenas uma possibilidade, em relação aos números de pontos flutuantes. Caso contrário, o Number A classe deixa o caminho de conversão inteiramente para os implementadores. Então, sim - ele não diz nada sobre isso. Eu não diria que é tão ruim, mas certamente é enganoso.

Não vejo sua pergunta, como isso é diferente do lixo que você recebe sempre que tenta representar um número fora dos limites de um tipo numérico específico?

final Number n = Long.MAX_VALUE;
System.out.println(n + " -> " + n.intValue());

impressões

9223372036854775807 -> -1

Deseja que a API lhe diga que você obterá saída inválida se passar a entrada inválida?

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top