我将底数b提高到幂p并取模m。

假设b = 55170或55172,而m = 3043839241(恰好是55171的平方)。 linux-calculator bc给出结果(我们需要此来进行控制):

echo "p=5606;b=55171;m=b*b;((b-1)^p)%m;((b+1)^p)%m" | bc
2734550616
309288627


现在计算55170 ^ 5606给出了一个较大的数字,但是由于我必须进行模运算,所以我认为可以避免使用BigInt,原因是:

(a*b) % c == ((a%c) * (b%c))%c i.e.
(9*7) % 5 == ((9%5) * (7%5))%5 =>
63 % 5    == (4     *    2) %5 =>
3         == 8 % 5


...并且a ^ d = a ^(b + c)= a ^ b * a ^ c,因此我可以将b + c除以2,从而得到ds d / 2和d-(d / 2),因此对于8 ^ 5,我可以计算8 ^ 2 * 8 ^ 3。

因此,我的(有缺陷的)方法总是动态地切断除数,如下所示:

def powMod (b: Long, pot: Int, mod: Long) : Long = {
      if (pot == 1) b % mod else {
          val pot2 = pot/2
          val pm1 = powMod (b, pot2, mod)
          val pm2 = powMod (b, pot-pot2, mod)
          (pm1 * pm2) % mod
      }
}


并提供了一些价值,

powMod (55170, 5606, 3043839241L)
res2: Long = 1885539617
powMod (55172, 5606, 3043839241L)
res4: Long = 309288627


如我们所见,第二个结果与上面的结果完全相同,但是第一个结果看起来很安静。我正在做很多这样的计算,只要它们保持在Int的范围内,它们似乎是准确的,但是我看不到任何错误。使用BigInt也可以,但是速度太慢:

def calc2 (n: Int, pri: Long) = {
    val p: BigInt = pri
    val p3 = p * p
    val p1 = (p-1).pow (n) % (p3)
    val p2 = (p+1).pow (n) % (p3)
    print ("p1: " + p1 + " p2: " + p2)
}

calc2 (5606, 55171)
p1: 2734550616 p2: 309288627


(与bc相同的结果)有人可以看到powMod中的错误吗?

最佳答案

我认为答案在这里:

scala> math.sqrt(Long.MaxValue).toLong < 3043839241L
res9: Boolean = true


这意味着即使数字小于该特定模块值,您也可能会长时间溢出。让我们尝试抓住它:

scala> def powMod (b: Long, pot: Int, mod: Long) : Long = {
     |       if (pot == 1) b % mod else {
     |           val pot2 = pot/2
     |           val pm1 = powMod (b, pot2, mod)
     |           val pm2 = powMod (b, pot-pot2, mod)
     |           val partial = ((pm1 % mod) * (pm2 % mod)).ensuring(res =>
     |             res > pm1 % mod && res > pm2 % mod, "Long overflow multiplying "+pm1+" by "+pm2)
     |           partial % mod
     |       }
     | }
powMod: (b: Long,pot: Int,mod: Long)Long

scala> powMod (55170, 5606, 3043839241L)
java.lang.AssertionError: assertion failed: Long overflow multiplying 3042625480 by 3042625480


你有它。

08-05 06:40