我正在使用Java中的一些算术运算,需要处理非常大的数字。
请参阅此简单的代码段:
// A = a^k mod p
double k = 96 , a = 13 , p = 353 ;
double A = (Math.pow(a,k))%p;
System.out.println(A);
这打印29.0。
当我使用我的Windows计算器时,它返回58.0(13 ^ 96)%353。 我知道计算器是正确的。
为什么这个Java代码打印出错误的结果?
答案 0 :(得分:3)
嗯,Math.pow
可能不会做你认为它做的事情。这不是你的错,实际上是骗你的。它会将合理关闭的double
返回到13 ^ 96,但不完全正确。由于我们在这里谈论一个大约10 ^ 107的数字,一个小的相对变化意味着一个绝对的变化远大于353.因此,所有关于此的赌注都是关闭的。
为了给这个添加更多数字,当我们使用十进制科学记数法时几乎出现同样的问题:商是practically one,但差异是around 2^91。 通常,浮点点数不适合整数运算,实际上你必然会遇到这些问题。
虽然可以使用大整数lib,但有一种更为基础的方法可以解决这个问题:执行binary exponentiation并在每一步中取模数。 如果你是初学者,这将教你比一些大的int lib的黑盒子。
答案 1 :(得分:1)
calcul 13^96
会产生数字:
86808413954902578113899124146033582025796522106191700214004730205740649831517648547259748010923363334343041
需要太多精度才能存储在double
类型
您可以使用BigInteger
:
BigInteger bK = new BigInteger("96");
BigInteger bA = new BigInteger("13");
BigInteger bP = new BigInteger("353");
BigInteger res = bA.modPow(bK, bP); // same as res = bA.pow(96).mod(bP);
System.out.println(res); // 58