【问题标题】:Why in one case multiplying big numbers gives a wrong result?为什么在一种情况下乘以大数字会产生错误的结果?
【发布时间】:2017-04-26 20:45:04
【问题描述】:

这可能看起来很简单,但我没有任何答案。 当我写:

 System.out.println (100 * 1000 * 10000 * 100000);
 System.out.println (100 * 1000 * 10000 * 100000.0);

它返回这些值:

276447232
1.0E14

我知道这与某些数据类型的最大值有关。但我只想明确回答为什么它会为两个方程返回这些精确值。如果有人可以向我解释这一点,我将非常感激。

第一个返回值与 int 数据类型的最大值不匹配,这就是我感到困惑的原因。我假设的第二个返回值是双精度或浮点值,但我不确定。

【问题讨论】:

  • “第一个返回值与 int 数据类型的最大值不匹配,这就是我感到困惑的原因”——它已经溢出了。它没有达到最大值并停留在那里。
  • 100000000000000 % (2^32) 是 276447232...
  • (是的,第二个值是双精度值——不清楚你在哪里混淆了。)
  • @JonSkeet 好的,谢谢。需要明确的是,第二个返回值应该是这样的,不是错误的值吗?

标签: java int multiplication primitive


【解决方案1】:

在表达式中

System.out.println (100 * 1000 * 10000 * 100000);

参数是int,结果超过了int 允许的最大值2147483647。这就是我们所说的溢出。根据Java Language Specification

如果整数乘法溢出,则结果是数学乘积的低位,以某种足够大的二进制补码格式表示。

取一个数的N个低位相当于计算这个数除以2^N的余数。在我们的例子中,N=32 因为int 存储在 32 位上。这就是为什么 Jon Skeet 回答说

100000000000000 % (2^32) 是 276447232。

在表达式中

System.out.println (100 * 1000 * 10000 * 100000.0);

三个第一因子100 * 1000 * 10000 的乘积得到1_000_000_000,它小于int 的最大值。最后一个乘法得到Binary Numeric Promotion,这意味着,在这种情况下,1_000_000_000 被转换(提升)为double,然后乘以100000.0

【讨论】:

  • 太棒了!谢谢!!
  • 请注意,只有最后一个乘法是使用 double 数学完成的,前两个仍然是使用 int 数学完成的。 100 * 1000 * 10000 = 1_000_000_000,仍然小于2_147_483_647,因此在这种情况下不会溢出,但不要误以为将最后一个文字更改为double 会导致整个表达式使用double 数学来完成。为确保整个表达式的 double 数学,更改第一个文字,所有其他文字也将被强制转换为 double,例如100d * 1000 * 10000 * 100000.
  • @Andreas,你是对的。我已修改我的答案以考虑您的评论。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-12-28
  • 1970-01-01
  • 2011-07-05
  • 1970-01-01
相关资源
最近更新 更多