将Long.MAX_VALUE转换为Float

OLI*_*KOO 5 java binary bit

通过将Integer转换为Float,Float转换为Long,Long转换为Int,我很开心,然后我对下面的这种行为感到困惑.

当我转换一个s代表Long.MAX_VALUE(63 1s)的字符串时,我得到了一个NumberFormatException预期的.因为Long是64位并且Integer是32位所以有额外的31 1.(这是我的猜测也许是另一个原因请纠正我,如果我错了)

但是我不知道为什么我NumberFormatException转换Long到时没有得到Float.Long再次是64位,Float就像32位一样Integer.我知道位被解释为不同的Float(IEEE 754浮点"单格式"位布局)但是所有其他额外的31位发生了什么?我真的迷失在这里......

此外,我如何得到9.223372E18这是1011111000000000000000000000000位串?那些0来自哪里?

public static void main(String[] args){
    String s = String.valueOf(Long.MAX_VALUE); 
    print(s); //prints 9223372036854775807
    print(Long.toBinaryString(Long.MAX_VALUE)); //prints 111111111111111111111111111111111111111111111111111111111111111
    //Integer.valueOf(s) this throws NumberFormatException because Long is 64 bits and Integer is 32 so s is too large to be an Integer
    print(Float.valueOf(s)); //prints 9.223372E18 Why no NumberFormatException? and how did it result 9.223372E18?

    float f = Float.valueOf(s);
    int intBits = Float.floatToIntBits(f); 
    print(Integer.toBinaryString(intBits)); //1011111000000000000000000000000 How come? s was a String of 1s now there are 0s?
}

public static <T> void print(T arg){
    System.out.println(arg);
} 
Run Code Online (Sandbox Code Playgroud)

rge*_*man 1

首先,我们来确认一下转换是否正确。

Long.MAX_VALUE是 9223372036854775807(19 位数字)。正如您所看到的,该值大约是您打印的值:9.223372E18

a 的精度long始终为1。然而,a 的精度float取决于数字的大小。

IEEE 单精度浮点数中,float尾数或存储的“小数”部分只有 24 位精度。因此 表示的实际值float是实际值 off 的近似值Long.MAX_VALUE

Float.floatToIntBits

正如您所发现的,该Float.floatToIntBits方法产生的位与原始long位表示不同。

根据 IEEE 754 浮点“单一格式”位布局返回指定浮点值的表示形式。位 31(由掩码 0x80000000 选择的位)表示浮点数的符号。位 30-23(由掩码 0x7f800000 选择的位)表示指数。位 22-0(由掩码 0x007fffff 选择的位)表示浮点数的有效数(有时称为尾数)。

(剪断)

返回: 表示浮点数的位。

此方法不会将其转换为,它仅给出恰好存储在 中的int位表示形式。由此表示的值预计不会与的值相同。floatintintfloat

转换

这些零是浮点数的尾数。longto的实际转换float涉及查找最高有效位的符号、查找值的大小以建立指数,以及将值的其余部分转换为尾数。

float由于 a在 的尺度上的精度Long.MAX_VALUE有限,因此会损失一些精度。最终结果是该float值稍微向上舍入。由于Long.MAX_VALUE2 的幂差 1,因此向上舍入会产生 2 的幂,尾数中显示为全零。

Math.ulp您可以使用(最后一位的单位)来查看数字范围内浮点值的精度。

Math.ulp(f)
Run Code Online (Sandbox Code Playgroud)

这产生

1.09951163E12
Run Code Online (Sandbox Code Playgroud)

float正如您所看到的,对于for来说差异相当大Long.MAX_VALUE。(相应的 ulpdouble2048.0. Large,但比此处的 ulp 小得多。)但它与几乎 10 19float的值的预期一致- 大约 7 位精度。float