Python 实现大整数乘法算法的示例代码


Posted in Python onSeptember 17, 2019

我们平时接触的长乘法,按位相乘,是一种时间复杂度为 O(n ^ 2) 的算法。今天,我们来介绍一种时间复杂度为 O (n ^ log 3) 的大整数乘法(log 表示以 2 为底的对数)。

介绍原理

karatsuba 算法要求乘数与被乘数要满足以下几个条件,第一,乘数与被乘数的位数相同;第二,乘数与被乘数的位数应为  2 次幂,即为 2 ^ 2,  2 ^ 3, 2 ^ 4, 2 ^ n 等数值。

下面我们先来看几个简单的例子,并以此来了解 karatsuba 算法的使用方法。

两位数相乘

我们设被乘数 A = 85,乘数 B = 41。下面来看我们的操作步骤:

将 A, B 一分为二,令 p = A 的前半部分 = 8,q = A 的后半部分 = 5 , r = B 的前半部分 = 4 ,s = B 的后半部分 =  1,n = 2。通过简单的数学运算:

A * B = pq * rs = (p * 10 + q) * (r * 10 + s)  = p * r * 10 ^ 2 + (p * s + q * r ) * 10 + q * s。

令 u = p * r,v =(p - q) * (s - r),w = q * s。所以 A * B =  u * 10 ^ 2 + (u + v + w) * 10 + w。

换成数值求解的过程如下:

A * B = 85 * 41 = (8 * 10 + 5) * ( 4 * 10 + 1) = 8 * 4 * 10 * 10 + (8 * 1 + 5 * 4) * 10 + 5 * 1。

其中 u = 8 * 4 = 32,v = (8 - 5) (1 - 4) = -9,w = 5 * 1 = 5。

所以,A * B = 32 * 100 + (32 - 9 + 5) * 10 + 5 = 3485。与长乘法所得结果一致。

四位数相乘

我们设被乘数 A = 8537,乘数 B = 4123。下面来看我们的操作步骤:

将 A, B 一分为二,令 p = A 的前半部分 = 85,q = A 的后半部分 = 37 , r = B 的前半部分 = 41 ,s = B 的后半部分 =  23,n = 4。

==> 其中,u = 85 * 41, v = (85 - 37) * (23 - 41), w = 37 * 23。

==> A * B = 8537 * 4123 = u * 10 ^ 4 + (u + v + w) * 10 ^ 2 + w =  3485_0000 +34_7200 + 851 = 35198051。

在我们计算 u, v,  w 的过程中又会涉及两位数的乘法,我们继续使用 Karatsuba 算法得出两位数相乘的结果。

N 位数相乘

我们令 n 为 乘数与被乘数的位数,令 p = A 的前半部分,q = A 的后半部分, r = B 的前半部分 ,s = B 的后半部分。

==> 其中, u = p * r,v = (p - q) * (s - r),w = q * s。

所以 A * B =  u * 10 ^ n + (u + v + w) * 10 ^ (n / 2) + w。

而 u, v, w 则是两个 n / 2 位的乘法运算。我们继续调用 Karatsuba 算法计算 u, v, w 的数值。接着,我们在计算 n / 2 乘法的过程中又会遇到 n / 4 位的乘法运算……以此类推,直到我们遇到两个个位数的乘法,我们就直接返回这两个个位数乘法的结果。层层返回,最终得到 N 位数的乘法结果。

时间复杂度

我们平常使用的长乘法,是 O (n ^ 2) 的时间复杂度。比如两个 N 位数相乘,我们需要将每一位按规则相乘,所以需要计算  N * N 次乘法。而使用  Karatsuba 算法每层需要计算三次乘法,两次加法,以及若干次加法,每使用一次 karatsuba 算法,乘法规模就下降一半。

所以,对于两个 n =  2 ^ K 位数乘法运算,我们需要计算 3 ^ k 次乘法运算。而 K = log n(底数为 2), 3 ^ K = 3 ^ log n = 2  ^ (log 3 * log n) = 2 ^ (log n * log 3) = n ^ log 3 (底数为 2)。

代码实现

from math import log2, ceil
 
def pad(string: str, real_len: int, max_len: int) -> str:
  pad_len: int = max_len - real_len
  return f"{'0' * pad_len}{string}"
 
 
def kara(n1: int, n2: int) -> int:
  if n1 < 10 or n2 < 10:
    return n1 * n2
  n1_str: str = str(n1)
  n2_str: str = str(n2)
  n1_len: int = len(n1_str)
  n2_len: int = len(n2_str)
  real_len: int = max(n1_len, n2_len)
  max_len: int = 2 ** ceil(log2(real_len))
  mid_len: int = max_len >> 1
  n1_pad: str = pad(n1_str, n1_len, max_len)
  n2_pad: str = pad(n2_str, n2_len, max_len)
  p: int = int(n1_pad[:mid_len])
  q: int = int(n1_pad[mid_len:])
  r: int = int(n2_pad[:mid_len])
  s: int = int(n2_pad[mid_len:])
  u: int = kara(p, r)
  v: int = kara(q-p, r-s)
  w: int = kara(q, s)
  return u * 10 ** max_len + (u+v+w) * 10 ** mid_len + w

输出结果:

==> kara(123456, 9734) == 123456 * 9734

==> kara(1234233456756, 32459734) == 1234233456756 * 32459734

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
python通过BF算法实现关键词匹配的方法
Mar 13 Python
python实现对一个完整url进行分割的方法
Apr 29 Python
Python字符串格式化
Jun 15 Python
用python处理MS Word的实例讲解
May 08 Python
Python动态导入模块的方法实例分析
Jun 28 Python
opencv实现图片模糊和锐化操作
Nov 19 Python
带你认识Django
Jan 15 Python
Pycharm和Idea支持的vim插件的方法
Feb 21 Python
Python打包工具PyInstaller的安装与pycharm配置支持PyInstaller详细方法
Feb 27 Python
django从后台返回html代码的实例
Mar 11 Python
Django分组聚合查询实例分享
Apr 29 Python
Django中的AutoField字段使用
May 18 Python
Python对接 xray 和微信实现自动告警
Sep 17 #Python
Python计算两个矩形重合面积代码实例
Sep 16 #Python
详解Python3 pickle模块用法
Sep 16 #Python
python scipy卷积运算的实现方法
Sep 16 #Python
python 三元运算符使用解析
Sep 16 #Python
python 利用pywifi模块实现连接网络破解wifi密码实时监控网络
Sep 16 #Python
Python循环实现n的全排列功能
Sep 16 #Python
You might like
用PHP函数解决SQL injection
2006/12/09 PHP
PHP XML数据解析代码
2010/05/26 PHP
yii实现级联下拉菜单的方法
2014/07/31 PHP
php验证手机号码
2015/11/11 PHP
PHP实现的AES 128位加密算法示例
2019/09/16 PHP
Thinkphp页面跳转设置跳转等待时间的操作
2019/10/16 PHP
Ajax::prototype 源码解读
2007/01/22 Javascript
jQuery 表单验证扩展代码(一)
2010/10/11 Javascript
jquery表单验证框架提供的身份证验证方法(示例代码)
2013/12/27 Javascript
JavaScript实现文字与图片拖拽效果的方法
2015/02/16 Javascript
FullCalendar日历插件应用之数据展现(一)
2015/12/23 Javascript
javascript中this指向详解
2016/04/23 Javascript
JS实现超简单的汉字转拼音功能示例
2016/12/22 Javascript
简单实现JS倒计时效果
2016/12/23 Javascript
实例分析JS与Node.js中的事件循环
2017/12/12 Javascript
Vue 拦截器对token过期处理方法
2018/01/23 Javascript
vue实现购物车抛物线小球动画效果的方法详解
2019/02/13 Javascript
vue.js多页面开发环境搭建过程
2019/04/24 Javascript
Vue Router history模式的配置方法及其原理
2019/05/30 Javascript
[02:09]抵达西雅图!中国军团加油!
2014/07/07 DOTA
[01:01:31]2018DOTA2亚洲邀请赛3月29日小组赛B组 Mineski VS paiN
2018/03/30 DOTA
Python中的并发编程实例
2014/07/07 Python
python3 遍历删除特定后缀名文件的方法
2018/04/23 Python
Django生成PDF文档显示在网页上以及解决PDF中文显示乱码的问题
2019/07/04 Python
使用sublime text3搭建Python编辑环境的实现
2021/01/12 Python
CSS3实现菜单悬停效果
2020/11/17 HTML / CSS
详解Canvas实用库Fabric.js使用手册
2019/01/07 HTML / CSS
中学老师的自我评价
2013/11/07 职场文书
电子信息专业学生自荐信
2013/11/09 职场文书
安全生产网格化管理实施方案
2014/03/01 职场文书
部队反四风对照检查材料
2014/09/26 职场文书
街道务虚会发言材料
2014/10/20 职场文书
2015年社区综治宣传月活动总结
2015/03/25 职场文书
《假如》教学反思
2016/02/17 职场文书
小公司融资,商业计划书的8切记
2019/07/15 职场文书
SQL IDENTITY_INSERT作用案例详解
2021/08/23 MySQL