引子

今天无意中,看到了慧科教育科技集团有限公司-后厂理工学院 的AI相关学员招募信息,要求颇高,还要做编程自测题,并且达到60分才建议进行课程的学习。我忍不住发送了报名信息,得到了自测题。看到了如下的一道题目:


快速幂取余算法实现

第一眼,看到题目,因为之前没有接触过快速幂算法,我心想,这也太简单了~~,于是分分钟做出了第一版的程序:

import mathdef count_factorial(x):result = 1for each in range(1, x + 1):result *= eachreturn resultdef function(a, b, c):return math.pow(a, count_factorial(b)) % cprint(function(2, 1, 2), 0)
print(function(3, 2, 2), 1)
print(function(1, 100000, 1), 0)

然后,报错了。

0.0 0
1.0 1
Traceback (most recent call last):File "D:/code/test2.py", line 17, in <module>print(function(1, 100000, 1), 0)File "D:/code/test2.py", line 12, in functionreturn math.pow(a, count_factorial(b)) % c
OverflowError: int too large to convert to float

这时我才意识到,原来这道题的重点,不是在于数学运算功能的实现,而是重点在于大数的运算。
因此,这是一倒算法题,
f(a,b,c)=ab!MODcf(a, b, c) = a^{b!} MODcf(a,b,c)=ab!MODc
算法的核心就是如何将上式的a 和 b!不断的减小,以免超出python定义的整形的最大长度。
PS: 公式中的 MOD 就是数学中取余的运算符 也就是程序中我们常用的 %

  1. 减小公式中a的方法

迅速百度查到如下已经被证明的定理:
积的取余等于每个数取余的乘积再取余
意思就是说,f(a,b,c)=ab!MODc=(aMODc)b!MODcf(a, b, c) = a^{b!} MODc= (a MODc)^{b!}MODcf(a,b,c)=ab!MODc=(aMODc)b!MODc
举个例子7^8%2 = (7%2)^8%2 = 1^8%2 = 1%2 = 1
这个数学定理有效的帮助我们减小了a 的值。

但是这还是远远不够!!因为b!(b的阶乘)会是一个更大的挑战。
2. 减小公式中b的方法(我们将b!作为一个很大的数用b来代替)
我们可以通过快速幂的方式来进行计算:

我们都知道指数的运算法则,ax+y=ax∗aya^{x+y} = a^{x}*a^{y}ax+y=ax∗ay 那么公式中的b!也可以通过拆分达到减小b的效果。
当b为偶数时:ab=ab/2∗ab/2=ab/2∗2=(a2)b/2a^{b} = a^{b/2}*a^{b/2}=a^{b/2*2}=(a^2)^{b/2}ab=ab/2∗ab/2=ab/2∗2=(a2)b/2
当b为奇数时:ab=a∗ab−1=a∗a(b−1)/2∗a(b−1)/2=a∗a(b−1)/2∗2=a∗(a2)(b−1)/2a^{b} = a*a^{b-1}=a*a^{(b-1)/2}*a^{(b-1)/2}=a*a^{(b-1)/2*2}=a*(a^2)^{(b-1)/2}ab=a∗ab−1=a∗a(b−1)/2∗a(b−1)/2=a∗a(b−1)/2∗2=a∗(a2)(b−1)/2

注意: 我们发现无论是奇数还是偶数,最后我们都会更新a为a^2并且将 b更新为b/2,只不过当b为奇数时先将b更新为b-1再将b更新为b/2

因此python实现的代码如下

# 计算输入的阶乘
def count_factorial(y):result = 1for each in range(1, y + 1):result *= eachreturn resultdef function(a, b, c):b = count_factorial(b)result = 1# 减小aa = a % cwhile b > 0:# 当b为奇数时if b % 2 == 1:result = (result * a) % cb -= 1b = b / 2# 不断的减小aa = (a ** 2) % creturn resultprint(function(2, 1, 2), 0)
print(function(3, 2, 2), 1)
print(function(1, 100000, 1), 0)
print(function(1, 100000, 2), 1)
print(function(99036, 92879, 77028), 0)
print(function(14916, 63624, 37968), 32544)
print(function(48778, 6070, 89146), 57188)

输出结果为:

D:\code\venv\Scripts\python.exe D:/code/test2.py
0 0
1 1
Traceback (most recent call last):File "D:/code/test2.py", line 29, in <module>print(function(1, 100000, 1), 0)File "D:/code/test2.py", line 21, in functionb = b / 2
OverflowError: integer division result too large for a floatProcess finished with exit code 1

原因是:

在python3中两个数做除法运算,无论除数和被除数是否为float型 结果都会被强制的转换为float,但是b是一个很大的数,虽然可以被python自己转换的长整形保存,但是他的一半依然很大无法被float型保存。因此我们无法使用除法进行计算。

解决方法:

使用位运算来做除法的运算。
PS:我们要注意位运算的除法相当于整除,不会保留余数。
举个例子:
2>>1 的结果为 1 但是 3>>1 的结果同样为 1 原因是3的二进制位11向右移一位变为二进制的1 也就是十进制的1。
也就是说,位运算帮助了我们做了当b为奇数时b=b-1的操作。

因此,我们的python代码如下:

# 计算输入的阶乘
def count_factorial(y):result = 1for each in range(1, y + 1):result *= eachreturn resultdef function(a, b, c):b = count_factorial(b)result = 1# 减小aa = a % cwhile b > 0:# 当b为奇数时if b % 2 == 1:result = (result * a) % c# b更新为b/2b = b >> 1# a更新为a^2 并 取余减小a的值a = (a ** 2) % creturn resultprint(function(2, 1, 2), 0)
print(function(3, 2, 2), 1)
print(function(1, 100000, 1), 0)
print(function(1, 100000, 2), 1)
print(function(99036, 92879, 77028), 0)
print(function(14916, 63624, 37968), 32544)
print(function(48778, 6070, 89146), 57188)

###算法优化
现在算法没有什么问题了,但是我们发现还存在很多可以优化的提高,来提高算法的效率。

f(a,b,c)=ab!MODcf(a, b, c) = a^{b!} MODcf(a,b,c)=ab!MODc

  1. 当a变为0之后,整个运算的答案也就为0
  2. 当a变为1之后,无论通过a = a^2 来更新a,a都为1,并且只要c的值不为1 那么(a^2)%c 依然为1,当c的值为1时,a会变为0走第一条所述的流程结果直接为0

通过优化算法得到python程序如下:

# 计算输入的阶乘
def count_factorial(y):result = 1for each in range(1, y + 1):result *= eachreturn resultdef function(a, b, c):b = count_factorial(b)result = 1# 减小aa = a % cwhile b > 0:# 当b为奇数时if b % 2 == 1:result = (result * a) % c# b更新为b/2b = b >> 1# a更新为a^2 并 取余减小a的值a = (a ** 2) % cif a == 0:return 0if a == 1:return resultreturn resultprint(function(2, 1, 2), 0)
print(function(3, 2, 2), 1)
print(function(1, 100000, 1), 0)
print(function(1, 100000, 2), 1)
print(function(99036, 92879, 77028), 0)
print(function(14916, 63624, 37968), 32544)
print(function(48778, 6070, 89146), 57188)

PS:这一条 function(14916, 63624, 37968) 由于数量级很大,运算既然很慢可能需要等几分钟。

运行结果如下:

D:\code\venv\Scripts\python.exe D:/code/test2.py
0 0
1 1
0 0
1 1
0 0
32544 32544
57188 57188Process finished with exit code 0

##后记
这是我在第一次写技术博客,希望我可以坚持下来不断的积累,得到成长。欢迎各位留言交流。

Python实现快速幂取余算法相关推荐

  1. 【面试相关】python实现快速幂取余算法详解

    假设我们要计算 2102^{10}210 对1000取模的结果,可以很简单的得到24.但是如果要求 210002^{1000}21000 对1000取模的结果,常规方法就行不通了,因为常规的变量无法容 ...

  2. 快速幂取余算法总结详解

    废话不多说, 直接步入正题. 现在oj网站的题或者竞赛的题,如果a的b次幂且b很大,那么题中大多会让你把结果对一个数取余也就是求模,例如a^b%c这种,当然如果是考高精度的题除外. 接下来我将提供一种 ...

  3. 【数学】幂运算与快速幂取余

    一.幂运算 1.幂的定义: 的幂就是多个相乘,记作,表示的次幂,即个相乘,我们把叫做底数,叫做指数. 2.幂的运算: 我们可以用公式将幂运算进行简化,公式如下: 3.求幂方法: (1). Python ...

  4. C语言快速幂取模算法小结

    资料链接:http://www.jb51.net/article/54947.htm C语言实现的快速幂取模算法,是比较常见的算法.分享给大家供大家参考之用.具体如下: 首先,所谓的快速幂,实际上是快 ...

  5. 快速幂||取余运算【模板】(洛谷P1226题题解,Java语言描述)

    题目要求 P1226题目链接 分析 标准的快速幂取模算法板子,之前这个算法我在这篇文章中讲过了:<快速幂算法详解&&快速幂取模算法详解>. 这里选择使用比较简单的API实现 ...

  6. 【算法分析与设计】快速幂算法与快速幂取模算法

    文章目录 快速幂算法 算法分析 算法实现 位运算优化 BigInteger支持 快速幂取模算法 算法优点 算法推导 算法实现 BigInteger支持 本文完整代码实现(Java语言描述) 快速幂算法 ...

  7. 快速幂(快速幂取余)

    引入公式 (a*b) %c = ((a % c)*(b % c)) %c 普通求幂的解法 public static int pow(int x,int n) {int result = 1;for ...

  8. 洛谷 P1226 【模板】快速幂||取余运算

    题目描述 给你三个整数 a,b,p,求 a^b mod p. 输入格式 输入只有一行三个整数,分别代表 a,b,p. 输出格式 输出一行一个字符串 a^b mod p=s,其中 a,b,p 分别为题目 ...

  9. P1226 【模板】快速幂||取余运算

    题目描述 给你三个整数 b,p,k,求 b^pmod . 输入格式 输入只有一行三个整数,分别代表 b,p,k 输出格式 输出一行一个字符串 b^p mod k=s,其中 b, p, k分别为题目给定 ...

最新文章

  1. 敏捷开发中Scrum方法
  2. 将 Firefox 浏览器的书签导出
  3. HDU 1536 求解SG函数
  4. [原创]DebugTools系列(4):AQTime经验总结
  5. 用jquery写一个属于自己的音乐播放器
  6. 赛我 v.s Fzone v.s 喔赛 用户体验对比分析
  7. XMLHTTP---介绍
  8. 01--DNS服务器2
  9. intouch historian 配置
  10. android应用程序开发另解及Android SDK工具集的另类用法 .
  11. 用什么软件测试固态硬盘坏没坏,SSD能用多久在哪看 检测固态硬盘寿命方法
  12. 变压器高低压侧的电流计算
  13. SQL(08)_SQL约束
  14. UE4-(蓝图)第四十四课过场动画之创建及动画添加
  15. 钉钉桌面版绑定其他邮箱
  16. 让QQ的文字漂亮起来
  17. 广告电商系统开发功能只订单处理
  18. 《计算机软件基础》实验一
  19. 常用的dns地址分享
  20. 面对物联网安全隐患高墙,熵核科技如何实现突围

热门文章

  1. 可控硅电路的电容电阻的作用
  2. 转载:数据库的相关书籍
  3. wpf资源的定义与使用(String类型)
  4. mongodb的时间差 8小时
  5. Rstudio中更新R
  6. Linux—系统启动过程
  7. #边学边记 第三章 信息系统安全、服务管理与规划之信息系统安全技术
  8. 2017-2018-2 20179216 《网络攻防与实践》第六周总结
  9. NOip2000税收与补贴问题
  10. matlab三相异步电动机,三相异步电动机仿真