Estou criando um valor float usando bits inteiros brutos, onde a mantissa tem todos os bits definidos como 1. No entanto, converter para double inverte o bit final para 0. Por que isso acontece? Pelo que tenho visto online, a conversão de float para double supostamente preserva a mantissa e o expoente, já que double pode acomodar todos os floats.
class Main {
public static void main(String[] args) {
float f = Float.intBitsToFloat((1 << 23) - 1);
// The following line gives 23 consecutive 1s representing a mantissa with all bits set to 1.
System.out.println(Integer.toBinaryString(Float.floatToIntBits(f)));
double d = f;
// The following line gives 11100000001111111111111111111111000000000000000000000000000000.
// The mantissa has 22 consecutive 1s not 23 like in the original float
System.out.println(Long.toBinaryString(Double.doubleToLongBits(d)));
}
}
Estou usando o JDK 17 e adicionar strictfp à função mantém esse comportamento. Recebo um aviso informando que strictfp não é mais necessário.
Esses números são iguais. A conversão não apresenta perdas.
Seu float é subnormal. Floats subnormais têm um bit inicial implícito de 0 em vez de 1 na mantissa.
Seu duplo está normal. Ele tem um bit inicial implícito de 1 na mantissa.
Incluindo o bit inicial implícito, ambos os números têm uma mantissa com 23 1s consecutivos.
Float to
double
não apresenta perdas, mas o arredondamento é tratado como padrão no padrão IEEE e, portanto, arredonda a mantissa para que o último bit seja par (para produzir arredondamento de probabilidade igual), mas não deve haver arredondamento nesse processo.De qualquer forma,
double
tem 53 bits de mantissa efloat
apenas 24, não deve haver nenhuma perda de precisão na conversão... todos os bits emfloat
têm sua contraparte emdouble
. Os primeiros 23 bits da mantissa (se bem me lembro, ofloat
tipo tem o bit mais significativo da mantissa implícito --- isto é, não representado, pois é sempre 1---, enquanto essa abordagem não for representada na memória)Nota: De fato, estou errado, o bit mais significativo de
double
também está implícito. Mas também é possível que o bit que você vê como zero seja devido a esse bit implícito que conta para precisão, mas não é usado, exceto para valores abaixo do normal .