将 Long.MAX_VALUE 转换为浮点数

Convert Long.MAX_VALUE to Float

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

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

但是我不确定为什么在将 Long 转换为 Float 时没有得到 NumberFormatExceptionLong 也是 64 位,而 Float 是 32 位,就像 Integer 一样。我知道位被不同地解释为 Float(IEEE 754 浮点 "single format" 位布局)但是所有其他额外的 31 位发生了什么?我真的迷路了....

此外,如何获得 1011111000000000000000000000000 位串 9.223372E18?这些 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);
} 

关于print(Float.valueOf(s)); //prints 9.223372E18 Why no NumberFormatException? and how did it result 9.223372E18?

浮点数的表示方式不同。根据Java Language Specification.

,有问题的数字在Float范围内

The JavaDoc

中描述了精确转换,包括舍入

关于`print(Integer.toBinaryString(intBits)); //1011111000000000000000000000000 怎么来的? s 是一个由 1 组成的字符串现在有 0 了吗?':

Float.floatToIntBits(f) 不 return "the same number as integer"。 它的语义在 The JavaDoc

中描述

一个float用四个字节(32位)表示,一个long用8个字节(64位)表示。当您将 long 转换为 float 时,您会丢失一半数据,因为您无法将 64 位转换为 32 位。这就是你丢失了很多位的原因。

float 使用 23 位尾数,因此大于 2^23 的整数将被截断。

这就是为什么你能够施法并且施法有结果的原因。

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

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

long 的精度总是 1。但是,float 的精度取决于数字的大小。

在一个IEEE single-precision floating point number中,也就是float,尾数只有24位精度,也就是存储的"fraction"部分。所以 float 表示的实际值是 Long.MAX_VALUE.

实际值的近似值

Float.floatToIntBits

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

Returns a representation of the specified floating-point value according to the IEEE 754 floating-point "single format" bit layout. Bit 31 (the bit that is selected by the mask 0x80000000) represents the sign of the floating-point number. Bits 30-23 (the bits that are selected by the mask 0x7f800000) represent the exponent. Bits 22-0 (the bits that are selected by the mask 0x007fffff) represent the significand (sometimes called the mantissa) of the floating-point number.

(剪断)

Returns: the bits that represent the floating-point number.

此方法不会将转换为int,它只给出恰好存储的float的位表示在 int 中。此 int 表示的值是 而不是 预期与 float.

的值相同

转换

那些零是浮点数的尾数。 longfloat 的实际转换涉及找到最高有效位的符号,找到值的大小以建立指数,并将其余值转换为尾数。

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

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

Math.ulp(f)

产生

1.09951163E12

如您所见,floatLong.MAX_VALUE 的差异相当大。 (对应的double的ulp是2048.0。大了,但是比这里的float的ulp小很多。)不过符合预期,差不多1019 -- float.

的精度约为 7 位