37

为什么我需要添加一个“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
4

2 回答 2

136
long oneYearWithL = 1000*60*60*24*365L;
long oneYearWithoutL = 1000*60*60*24*365;

您的第一个值实际上是 long (因为365L是 a long,并且1000*60*60*24是 a integer,所以带有值的值的结果是一个multiplying值。longintegerlong

但是第二个值是一个整数(因为你只是将一个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);

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

输出: -

31536000000
1471228928
2147483647

所以,你可以看到区别..

011101010111101100010010110000000000 -- Binary equivalent of 1000*60*60*24*365L
    01111111111111111111111111111111 -- Binary equivalent of Integer.MAX_VALUE

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

所以,字符串变成..

(0111)01010111101100010010110000000000 -- Remove the most significant bits..
      01010111101100010010110000000000 -- Binary equivalent of 1471228928

(作为输出得到)


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

例如: -

long thirtyYearWithL = 1000*60*60*24*30*365L;

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

2592000000 = 10011010011111101100100000000000  -- MSB is `1`, a negative value
             01100101100000010011100000000001  -- 2's complement representation

表示的十进制表示2's complement1702967297。因此,在乘以 之前2592000000转换为。现在,因为这个值适合: - ,所以它不会被进一步截断。-1702967297365Linteger range[-2147483648 to 2147483647]

因此,实际结果将是:-

long thirtyYearWithL = 1000*60*60*24*30*365L;
                     = 2592000000 * 365L;
                     = -1702967297 * 365L = -621583063040

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


更新 2: -

所以,而不是: -

long thirtyYearWithL = 1000*60*60*24*30*365L;

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

long thirtyYearWithL = 365L*1000*60*60*24*30; // will give you correct result

因为,现在您的temporary结果将是 type long,并且能够保持该值。

于 2012-10-06T09:08:22.697 回答
15

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

Java 默认为 32 位整数类型。Long的L64 位。通过放置Lafter 365,您告诉编译器将 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,则必须选择双精度值集。
    • 如果乘法表达式不是 FP-strict:
      • 如果乘法表达式的类型是float,则可以根据实现的心血来潮选择浮点值集或浮点扩展指数值集。
      • 如果乘法表达式的类型是double,则可以根据实现的心血来潮选择双精度值集或双扩展指数值集。

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

如果乘积的量级太大而无法表示,我们说操作溢出;结果是无限的适当符号。

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

尽管可能会发生上溢、下溢或信息丢失,但乘法运算符的求值*永远不会引发运行时异常。

于 2012-10-06T09:21:47.313 回答