在 Java 中键入转换。加倍到长

Type casting in Java. Double to long

为什么 System.out.println((long)Math.pow(2,63));System.out.println((long)(Math.pow(2,63)-1)); 在 Java 中的输出相同?

你应该使用括号来合并结果然后减去 1,像这样:

    System.out.println((long)Math.pow(2,63));

    System.out.println(((long)(Math.pow(2,63))-1));

输出:

9223372036854775807

9223372036854775806

输出相同,因为 double 没有足够的位来准确表示 263

一个double的尾数只有52位:

这最多为您提供 17 位十进制数字的精度。另一方面,您计算的值是 9223372036854775808,因此需要 19 位数字才能准确表示。结果,263 的实际表示为 9223372036854776000:

  • 尾数设置为1.0(隐含前面1)
  • 指数设置为 1086(隐式减去 1024 得到 63)

1表示的尾数相同,而有效值为零时指数为1024,即两个数的指数相差63,大于尾数.

当您的数字表示为 double 时会减去 1。由于被减数的量级远大于减数的量级,所以整个减法运算被忽略

减去更大的数字后您会得到相同的结果 - 一直到 512,即 29 (demo)。之后指数的差异将小于 52,因此您将开始得到不同的结果。

对于java中的long数据类型,最大值为9,223,372,036,854,775,807(含)。 (2^63 -1)

所以即使你尝试

System.out.println((long)Math.pow(2,65));
System.out.println((long)(Math.pow(2,63)-1));

输出

9223372036854775807
9223372036854775807

Math.pow( double, double ) returns 个 double 值。

double in java 是 64 位 IEEE 754 浮点数。(https://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html)

如果你看这里:https://en.wikipedia.org/wiki/Double-precision_floating-point_format 你会发现,这个格式由:

  • 1 位符号
  • 11 位指数
  • 53 位有效精度

pow 返回的数字需要更高的精度 (63) 才能准确存储。

基本上您添加的 1 低于此精度阈值。

相比之下,long 具有 64 位精度。

为了更清楚,假设我们使用的是十进制而不是 base2:

在一些假想的精度为 2 的小型浮点数据类型中,值 1000 将存储为 1.00e3。如果您加 1,则必须将其存储为 1.001e3。但是因为我们只有 2 的精度,它只能存储 1.00e3 并且没有任何变化。所以1.00e3 + 1 == 1.00e3

在您的示例中也会发生同样的情况,只是我们处理的是更大的数字和 base2 的原因。