Java:大整数错误

3

我正在尝试在Java中执行以下数学方程:

(44334*(220*220))+ (81744*220) + 39416)

当我在WolframAlpha(或谷歌)输入相同的等式时,我得到的结果是:
2163788696

在Java中我得到了负数。

我一直努力找出这是为什么,但没有成功。

我还尝试用BigInteger保存答案,但由于数字太大,结果变成了负值。

我应该怎么办?

6个回答

6

编辑:为了处理整数溢出问题,请使用long

System.out.println("Result: " +
    (44334L * 220 * 220 + 81744 * 220 + 39416));  // 2163788696

加号运算符是左结合的(无论是用于字符串连接还是加法),因此如果整个算术表达式没有括号,它将从左到右将子表达式的结果作为单独的字符串进行连接。
左操作数决定了+是用于字符串连接还是加法。在这种情况下,第一个操作数是一个字符串,因此右侧((44334*(220*220)))也被转换为一个字符串。第一个+运算符的结果是一个字符串,并用作另一个+字符串连接操作的左侧。下一个操作数((81744*220))再次被转换为一个字符串。
你可以在整个算术表达式周围加上括号来避免这种情况。

2

现在,你正在做的事情相当于:

System.out.println(("result="+(44334*220*220)) + (81744*220 + 39416) );
// = "result=2145765600" + 18023096
// = "result=214576560018023096"

括号很重要!这是您修复的代码:
System.out.println("result=" + (44334*220*220+ 81744*220 + 39416) );
// = "result=2163788696"

编辑:

还要注意自动int类型转换。使用long类型,因为你的结果大于MAX_INT(但小于MAX_LONG,即9223372036854775807)。

(long)((long)44334*220*220 + (long)81744*220 + 39416)

或者在数字后面加上后缀L(这样它们就被视为long)。

好的,现在我得到了负数结果,我该如何修复它? - phedon rousou
我尝试使用bigInteger,但是没有成功,也尝试了long,但是完全没有运气。 - phedon rousou
尝试:(long)((long)44334*220*220+ (long)81744*220 + 39416) - mbinette
很高兴能帮忙!我会在我的答案里添加评论。 - mbinette

2
问题出在表达式从左至右计算。第一个值是字符串类型,因此 + 运算符变成了字符串连接运算符而不是数学加法运算符。接下来,表达式 (44334*(220*220)) 和 (81744*220) 被计算并转换为字符串,导致了错误的结果。如果您用括号把整个表达式包围起来,结果将被正确计算,您将看到正确的结果。

1
问题在于Java中的+运算符被重载了。它既可以表示字符串连接,也可以表示数字相加。问题是有些+操作被视为字符串连接而不是数值相加。
您需要在表达式周围添加一组括号,以明确指定运算顺序,或者将操作数转换为数字类型,以避免这种混淆。
System.out.println("result="+((44334*(220*220))+ (81744*220) + 39416)); 

或者使用一个临时变量。

int res = (44334*(220*220))+ (81744*220) + 39416;
System.out.println("result="+res);

Java用于确定+含义的“规则”大致如下:
  • 如果左侧右侧操作数的类型为String,则+表示字符串连接。
  • 如果左侧右侧操作数的类型均为原始数字类型或数字包装类型,则+表示数字相加。
  • 否则,这是一个编译错误。

这里的另一个问题是2163788696大于最大的int值- 2147483647。因此,为了得到正确的答案(避免溢出),您需要告诉Java使用long算术;例如:
System.out.println("result=" + ((44334L * (220 * 220)) + (81744 * 220) + 39416));

如果不这么做,result将是一个负数...就像这个例子一样。
你也可以使用BigInteger,但它有点繁琐,而long在这里完全足够了。

你会遇到困难,因为结果大于 MAX_INT。;-) - mbinette
是的,这就是现在的问题,我尝试使用BigInteger但仍然没有成功。有什么想法吗? - phedon rousou
只用一个long行吗?但我不确定你是否还需要转换中间结果。 - OneMore
据我所知,Nop最多只有9位数字,但这里有10位数字。(我尝试过了,仍然得到了负数) - phedon rousou
我不记得Java中的中间计算规则是什么。如果其中一个成员不是long,它会转换回int吗? - 不会。如果任何一个操作数是long,则结果为long。通常,结果类型是参数类型中“更宽”的类型...但整数字面量的处理方式不同。 - Stephen C
显示剩余4条评论

1

对于 BigInteger 版本,请尝试这个,它会正确地工作。

BigInteger a = new BigInteger("44334").multiply(new BigInteger("220").multiply(new BigInteger("220")));
BigInteger b = new BigInteger("81744").multiply(new BigInteger("220"));
BigInteger c = new BigInteger("39416");
c = c.add(a).add(b);

System.out.println("resultVersA="+(44334*(220*220))+ (81744*220)  + 39416 );
System.out.println("resultVersB="+ c);

结果将是:

resultVersA=21457656001798368039416

resultVersB=2163788696

太好了,这个方法正常运行了。谢谢。我的错误在于我没有每次创建新的BigInteger。 - phedon rousou
为了方便,因为我将在带有变量而非数字的等式中使用它,我对此进行了中间转换,(long)((long)44334220220+ (long)81744*220 + 39416),这样可以正常运行。 - phedon rousou
你知道如何将bigInt转换为int吗?(在某个点上,结果会变小(通过使用模运算),然后我就能将其存储到一个int变量中) - phedon rousou
是的,您可以使用intValue方法,但如果数字大于最大int,则会出现问题。 - Mihai M.
BigInteger c = new BigInteger("39416"); 使用 c.intValue(); - Mihai M.
谢谢,显然,这个长可能有点限制 :) - phedon rousou

0

在你写下每个数字后面加上一个 L 就可以了。

(44334L*(220L*220L))+ (81744L*220L) + 39416L

谢谢,但这些数字只是示例,我会在方程中使用相当大的变量。所以我认为它不适用于变量名称。 - phedon rousou
使用 long 类型参数(而不是 int)就行了。 - Hakan Serce

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接