使用递归计算大数的幂

Posted

技术标签:

【中文标题】使用递归计算大数的幂【英文标题】:Using recursion to calculate powers of large digit numbers 【发布时间】:2015-12-10 20:32:59 【问题描述】:

我们的目标是使用递归计算大数提升到其他大数,例如,100 位数字提升到另一个 100 位数字。

我的计划是递归计算 exp/2,其中 exp 是指数,并根据 exp 是偶数还是奇数进行额外计算。

我当前的代码是:

def power(y, x, n):
    #Base Case
    if x == 0:
        return 1

    #If d is even
    if (x%2==0): 
        m = power(y, x//2, n)
        #Print statment only used as check
        print(x, m)
        return m*m

    #If d is odd
    else:
        m = y*power(y, x//2, n)
        #Print statement only used as check
        print(x, m)
        return m*m

我遇到的问题是它进行了太多计算,我正在努力弄清楚如何解决它。例如,2^3 返回 64,2^4 返回 256,2^5 返回 1024,依此类推。它计算 m*m 的次数太多了。

注意:这是求解大数模的一部分。我正在严格测试我的代码的指数部分。

【问题讨论】:

您的缩进(至少在问题方面)不正确。 此外,太多是什么意思。请提供一个例子,并说明您认为哪些语句不应该出现...... 哦,输入的时候一定没有意识到,谢谢! @CommuSoft:除非你有很多字节的 RAM,否则 bignums 不会削减它。 @jboyda5,你不需要写这个函数。使用内置的pow() 【参考方案1】:

首先,您的实现有一个奇怪的地方:您使用了一个从未使用过的参数n,而只是继续传递并且您从不修改。

其次第二次递归调用不正确:

else:
    m = y*power(y, x//2, n)
    #Print statement only used as check
    print(x, m)
    return m*m

如果你做数学,你会看到你返回:(y yx//2)2=y2*(x //2+1)(注意// 而不是/),因此一个y 太多了。为了正确执行此操作,您应该将其重写为:

else:
    m = power(y, x//2, n)
    #Print statement only used as check
    print(x, m)
    return y*m*m

(因此从m 部分中删除y* 并将其添加到return 语句中,这样它就不是平方的)。

这样做将使您的实现至少在语义上合理。但它不会解决性能/内存方面的问题。

您的comment 明确表示您想对结果进行取模,所以这可能是 Project Euler

策略是利用模在乘法下闭合的事实。换句话说,以下成立:

(a b) mod c = ((a mod c) * (b mod c)) mod c

您可以在您的程序中使用它来防止生成巨大的数字,从而处理需要很少计算工作量的小数字。

另一个优化是您可以简单地在参数中使用正方形。所以更快的实现是这样的:

def power(y, x, n):
    if x == 0: #base case
        return 1
    elif (x%2==0): #x even 
        return power((y*y)%n,x//2,n)%n
    else: #x odd
        return (y*power((y*y)%n,x//2,n))%n

如果我们用这个函数做一个小测试,我们看到两个结果对于小数字是相同的(pow() 可以在合理的时间/内存中处理):(12347**2742)%1009 返回787L 和@987654334 @787,所以它们产生了相同的结果(当然这不是证明),两者是等价的,只是一个过滤掉明显错误的简短测试。

【讨论】:

感谢所有帮助。我假设通过将 y 乘以 power(y, x, n) 将产生与在 return 语句中乘以 y 相同的结果。【参考方案2】:

根据这个问题的 c 版本,这是我的方法,它适用于正面和负面的暴露:

def power(a,b):
  """this function will raise a to the power b but recursivelly"""
  #first of all we need to verify the input
  if isinstance(a,(int,float)) and isinstance(b,int):
    if a==0:
      #to gain time
      return 0
    if b==0:
        return 1
    if b >0:
      if (b%2==0): 
      #this will reduce time by 2 when number are even and it just calculate the power of one part and then multiply 
        if b==2:
          return a*a
        else:
          return power(power(a,b/2),2)
      else:
      #the main case when the number is odd
        return a * power(a, b- 1)
    elif not b >0:
      #this is for negatives exposents
      return 1./float(power(a,-b))
  else:
    raise TypeError('Argument must be interfer or float')

【讨论】:

以上是关于使用递归计算大数的幂的主要内容,如果未能解决你的问题,请参考以下文章

大数乘法,递归计算50的阶乘

课程作业03:用递归方法计算组合数解决汉诺塔问题判断某个字符串是否回文

计算给定递归函数的精确运行时间(时间复杂度)

递归(计算组合数判断回文字符串汉诺塔问题)

大数计算问题

leetcode递归练习总结