将两个正整数乘以长的铸造结果为负值

Rom*_*ych 5 java android jvm dalvik

我有这样的代码:

int a = 629339;
int b = 4096;
long res = a*b;
Run Code Online (Sandbox Code Playgroud)

结果是,-1717194752 但如果我添加一个手动转换为长long res = ((long)a)*b;long res = (long) a*b;结果是正确2577772544 谁可以解释它是如何工作的.

SLa*_*aks 6

a*b 是一个整数,而不是一个长整数.

因为它只是一个整数,所以它已经绕过了32位的限制.
将此整数强制转换为long将不会神奇地恢复该数据.


kos*_*osa 5

long res = a*b;
Run Code Online (Sandbox Code Playgroud)

a*b 将被视为整数,除非您在结束(或)强制转换时添加 'l'。

根据java教程

int 数据类型是一个 32 位有符号二进制补码整数。它的最小值为 -2,147,483,648,最大值为 2,147,483,647(含)。对于整数值,此数据类型通常是默认选择,除非有理由(如上述)选择其他类型。


Ste*_*n C 5

您必须将赋值语句分解为其部分以了解正在执行的操作:

long res = a*b;
Run Code Online (Sandbox Code Playgroud)

第1步是获得的数值ab.

第2步是评估a * b.由于ab都是ints,这是一个int乘法.因此,我们乘629339629339这将是2577772544.不幸的是,2577772544它大于最大可能的Java int值...因此乘法运算会无声地溢出 ...而我们得到了-1717194752.

步骤3我们将RHS的值分配给LHS.由于RHS是int与LHS是float,在JLS说,我们进行原始加宽转换......它只是将-1717194752变成long具有相同的值.然后将加宽的值分配给res.


为了得到你期望的答案,我们必须强制使用long算术执行乘法.例如:

long res = ((long) a) * b;
Run Code Online (Sandbox Code Playgroud)

在这种情况下,我们有一个乘法long通过int,这是通过加宽处理intlong和进行long繁殖.这不再溢出(因为2577772544远低于long最大值),所以当我们最终赋值时res,它就是你期望的数字.