在java中处理大数字时的算术错误

时间:2018-04-27 17:43:24

标签: java numbers

我正在使用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代码打印出错误的结果?

2 个答案:

答案 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