Java中大数取模结果异常:long溢出导致错误值
为什么long类型相乘后取模结果不符合预期?
问题代码
long a = (long) 10e9+7; long b = (a * a); System.out.println("b is " + b); System.out.println("b%a is " + (b%a)); System.out.println(); BigInteger A = BigInteger.valueOf((long) 10e9+7); BigInteger B = A.multiply(A); System.out.println("B is " + B.longValue()); System.out.println("B.mod(A) is " + B.mod(A));
输出结果
b is 7766279771452241969 b%a is 6015846137 ///->>> why ?? overflow B is 7766279771452241969 //// -> should not overflow B.mod(A) is 0
原因分析
- long类型的溢出本质:Java中
long是64位有符号整数,最大值为9223372036854775807(约9.2×10^18)。你的代码里a的值是10000000007((long)10e9将double类型的10000000000转为long,加7后得到),它的平方是100000000140000000049,这个数值远大于long的最大值,执行a * a时直接触发整数溢出。 - 溢出后的数值是截断值:Java对整数溢出不会抛出异常,只会保留结果的低64位二进制位,因此
b存储的是溢出截断后的错误值,而非真实的a*a。此时用这个错误值对a取模,结果自然不是0——因为它已经不再是a的整数倍了。 - BigInteger的正确处理:
BigInteger是任意精度的整数类型,能完整存储超大数值,不会发生溢出,因此B是a*a的真实值,B.mod(A)计算真实平方值对a取模,结果必然为0。而B.longValue()只是将高精度数值强制转换回long,此时同样会触发截断,得到和b一致的溢出值,但这只是转换后的结果,BigInteger内部始终保存着正确的完整数值。
内容的提问来源于stack exchange,提问作者Pawan Patel
相关产品推荐
相关产品推荐

