为什么这两个乘法运算会得到不同的结果?

far*_*eed 37 java int operation multiplication long-integer

为什么我需要添加"L"字母才能获得正确的长值?另一个价值是什么?

long oneYearWithL = 1000*60*60*24*365L;
long oneYearWithoutL = 1000*60*60*24*365;
System.out.println(oneYearWithL);//gives correct calculation result : 31536000000
System.out.println(oneYearWithoutL)//gives incorrect calculation result: 1471228928
Run Code Online (Sandbox Code Playgroud)

Roh*_*ain 133

long oneYearWithL = 1000*60*60*24*365L;
long oneYearWithoutL = 1000*60*60*24*365;
Run Code Online (Sandbox Code Playgroud)

你的第一个值实际上是一个long(因为365L是a long,而且1000*60*60*24是a integer,所以multiplyinglong值的integer值的结果是一个long值.

但是第二个值是一个整数(因为你只是integer一个integer值只是一个值.所以结果将是一个32-bit整数.现在获得的结果multiplication是在整数的实际范围之外.所以,在分配给变量之前,它被截断以适合有效的整数范围.

看看以下打印声明: -

System.out.println(1000*60*60*24*365L);
System.out.println(1000*60*60*24*365);
System.out.println(Integer.MAX_VALUE);
Run Code Online (Sandbox Code Playgroud)

当您运行上面的代码时: -

输出: -

31536000000
1471228928
2147483647
Run Code Online (Sandbox Code Playgroud)

所以,你可以看到差异..

011101010111101100010010110000000000 -- Binary equivalent of 1000*60*60*24*365L
    01111111111111111111111111111111 -- Binary equivalent of Integer.MAX_VALUE
Run Code Online (Sandbox Code Playgroud)

因此,如果您不在L数字的末尾添加,则从第一个二进制字符串中删除4个最高有效位.

所以,字符串变成..

(0111)01010111101100010010110000000000 -- Remove the most significant bits..
      01010111101100010010110000000000 -- Binary equivalent of 1471228928
Run Code Online (Sandbox Code Playgroud)

(你得到的输出)


更新: - 从上面的解释,你也可以理解,即使在第一个赋值中,如果你multiplicationintegers乘以之前的结果365L超出范围,那么它将被截断以适应整数范围,或转换为2's complement representation如果需要,那么只有它会乘以long value - 365L.

例如: -

long thirtyYearWithL = 1000*60*60*24*30*365L;
Run Code Online (Sandbox Code Playgroud)

在上面的例子中,考虑第一部分 - 1000*60*60*24*30.这种乘法的结果是: - 2592000000.现在让我们看看它是如何表现的binary equivalent: -

2592000000 = 10011010011111101100100000000000  -- MSB is `1`, a negative value
             01100101100000010011100000000001  -- 2's complement representation
Run Code Online (Sandbox Code Playgroud)

表示的十进制2's complement表示是1702967297.因此,在被乘之前2592000000转换-1702967297365L.现在,这个值适合于integer range: - [-2147483648 to 2147483647],因此它不会被进一步截断.

那么,实际结果将是: -

long thirtyYearWithL = 1000*60*60*24*30*365L;
                     = 2592000000 * 365L;
                     = -1702967297 * 365L = -621583063040
Run Code Online (Sandbox Code Playgroud)

所以,所有这些东西只考虑type应用算术运算的最终结果的实际情况.并且对从left to right(考虑具有left-to-right关联性的运算符)的操作的每个临时结果执行该检查.如果发现任何临时结果超出范围,则在进行下一操作之前,将其相应地转换为适合所需范围.


更新2: -

所以,而不是: -

long thirtyYearWithL = 1000*60*60*24*30*365L;
Run Code Online (Sandbox Code Playgroud)

如果你365L在开始时移动你,那么你将得到正确的结果: -

long thirtyYearWithL = 365L*1000*60*60*24*30; // will give you correct result
Run Code Online (Sandbox Code Playgroud)

因为,现在你的temporary结果将是类型long,并且能够保持该值.

  • 这是我见过的最精美明确的答案之一. (4认同)

Ste*_*ath 15

如果没有L您的计算,则执行32位值.如果将值表示为十六进制,则较小的值只是较大值的较低4个字节.

Java默认为32位整数类型.的L,时间不长,是64位.通过把L365,你告诉编译器把365的long值.当32位和64位值相乘时,编译器将32位值向上转换为64位,以便评估表达式的中间结果保留整个64位范围.

请参阅Java语言规范中的原语类型和值.

乘法的行为在https://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.17.1中明确定义,如下所示:

15.17.1乘法运算符*

二元*运算符执行乘法运算,生成其操作数的乘积.如果操作数表达式没有副作用,则乘法是可交换操作.当操作数都是相同类型时,整数乘法是关联的,而浮点乘法不是关联的.如果整数乘法溢出,则结果是数学乘积的低阶位,如某些足够大的二进制补码格式所示.结果,如果发生溢出,则结果的符号可能与两个操作数值的数学乘积的符号不同.

浮点乘法的结果由IEEE 754算法规则控制:

  • 如果是任一操作数NaN,则结果为NaN.
  • 如果结果不是NaN,如果两个操作数具有相同的符号,则结果的符号为正,如果操作数具有不同的符号,则结果的符号为负.
  • 无穷大乘以零会导致NaN.
  • 无穷大乘以有限值会产生有符号无穷大.该标志由上述规则确定.
  • 在剩余的情况下,无论是无穷大还是NaN,都会计算出精确的数学乘积.然后选择一个浮点值集:
    • 如果乘法表达式是FP-strict(第15.4节):
      • 如果乘法表达式的类型是float,则必须选择浮点值集.
      • 如果乘法表达式的类型是double,则必须选择double值集.
    • 如果乘法表达式不是FP严格的:
      • 如果乘法表达式的类型是float,则可以在实现的奇思妙想中选择浮点值集或浮点扩展指数值集.
      • 如果乘法表达式的类型是double,则可以在实现的奇思妙想中选择double值set或double-extended-exponent值set.

接下来,必须从所选择的值集中选择一个值来表示产品.

如果产品的大小太大而无法表示,我们说操作溢出; 结果是无穷无尽的适当标志.

否则,使用IEEE 754舍入到最接近模式将产品四舍五入到所选值集中的最接近值.Java编程语言需要支持IEEE 754(§4.2.4)定义的逐渐下溢.

尽管可能发生溢出,下溢或信息丢失,但乘法运算符的求值从*不会引发运行时异常.