乘法发生溢出

Overflow occurs with multiplication

long m = 24 * 60 * 60 * 1000 * 1000;

以上代码产生了溢出并且没有打印出正确的结果。

long m2 = 24L * 60 * 60 * 1000 * 1000;
long m3 = 24 * 60 * 60 * 1000 * 1000L;

以上两行打印出正确的结果。

我的问题是-

  1. m2m3 对我使用的编译器有影响吗?
  2. java 是如何开始繁殖的?从左到右还是从右到左?是先计算 24*60 还是先计算 1000*1000?

在这种情况下 -

long m = 24 * 60 * 60 * 1000 * 1000;  

先评估赋值权。右边没有 long 类型的数据。都是int。所以 JVM 尝试将结果放入 int 然后发生溢出。

在第二种情况下 -

long m2 = 24L * 60 * 60 * 1000 * 1000;
long m3 = 24 * 60 * 60 * 1000 * 1000L;

这里乘法的一个操作数是long。所以其他人会自动提示long。结果试图适应 long。最后用 m2m3 完成赋值。

是的,乘法的结合性从左到右 - 意味着先取左操作数。基于这个事实,我认为在这种情况下我们应该使用 -

long m2 = 24L * 60 * 60 * 1000 * 1000;  

这个语句,因为在这个语句中升级到 long 发生得更早,这降低了溢出的风险。

我会使用 m2 行而不是 m3 行。

Java 从 left to right 计算乘法运算符 *,因此首先计算 24 * 60

碰巧24 * 60 * 60 * 1000(一个1000)没有溢出,所以当你乘以1000L(第二个1000) , 乘积在相乘前被提升为 long ,所以不会发生溢出。

但是正如您在评论中提到的,在乘以最后一个 long 数字之前,更多因素可能导致 int 数据类型溢出,从而产生不正确的答案。最好对第一个(最左边的)数字使用 long 文字,如 m2 中那样,以避免从一开始就溢出。或者,您可以将第一个文字转换为 long,例如(long) 24 * 60 * ....

从左到右相乘,int * int 产生 int。所以

24 * 60 * 60 * 1000 * 1000

相同
(((24 * 60)* 60) * 1000) * 1000

这给了我们

(((1440)* 60) * 1000) * 1000
((  86400   ) * 1000) * 1000
(    86400000       ) * 1000

最后由于整数溢出(因为 86400000000 对于最大值为 2147483647 的整数来说太大)结果将是

500654080

您可以通过使用 long 作为参数之一来消除整数溢出(int * longlong * int 产生 long)。

在这种情况下,您可以像在 m2 的情况下那样在开始时执行此操作:24L * 60 将产生 long 1440L 再次乘以int 60 产生新的 long,依此类推,只产生 long 值。

m3 案例在这里有效,因为您将 86400000 乘以 1000L,这意味着您正在避免整数溢出,因为结果将是 long.

Since expressions are evaluated from left to right,我更喜欢你的第一个解决方案 (m2 = ...)。

推理:让我们看一个稍微不同的例子。

long g = Integer.MAX_VALUE * 2 * 2L;

此表达式的计算结果为 -4,因为只有最后一次乘法将第一个表达式转换为 long(此时为 -2,因为两个操作数都是 int).如果你写

long g = Integer.MAX_VALUE * 2L * 2;

相反,g 将保留 8589934588 的预期值,因为第一个乘法产生 long.

类型的结果

让我们乘以更多的数字,即使有 1000L:

这一行也会溢出
long m3 = 24 * 60 * 60 * 1000 * 1000 *  1000 * 1000L;

虽然这会给出正确的结果:

long m3 = 24L * 60 * 60 * 1000 * 1000 *  1000 * 1000;

所以我们确定 java 从左到右开始相乘,我们必须从左边开始 Long 以防止溢出。

这是因为当我们使用 long 作为一个操作数时,另一个所有 int 类型的操作数都会被提示为 long

java 中的表达式从左到右求值。