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中argparse模块用法实例详解
Jun 03 Python
wxPython使用系统剪切板的方法
Jun 16 Python
Python 自动刷博客浏览量实例代码
Jun 14 Python
如何利用python查找电脑文件
Apr 27 Python
利用Python对文件夹下图片数据进行批量改名的代码实例
Feb 21 Python
Python实现一个数组除以一个数的例子
Jul 20 Python
python实现最大优先队列
Aug 29 Python
Django跨域请求原理及实现代码
Nov 14 Python
python对输出的奇数偶数排序实例代码
Dec 04 Python
使用BeautifulSoup4解析XML的方法小结
Dec 07 Python
python中常用的数据结构介绍
Jan 12 Python
使用pipenv管理python虚拟环境的全过程
Sep 25 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 注入攻击的技术实现以及预防办法
2011/01/27 PHP
php操作redis中的hash和zset类型数据的方法和代码例子
2014/07/05 PHP
php删除左端与右端空格的方法
2014/11/29 PHP
PHP读取并输出XML文件数据的简单实现方法
2017/12/22 PHP
JavaScript获取GridView选择的行内容
2009/04/14 Javascript
Mootools 1.2教程 滑动效果(Slide)
2009/09/15 Javascript
jQuery选择器的工作原理和优化分析
2011/07/25 Javascript
jQuery验证Checkbox是否选中的代码 推荐
2011/09/04 Javascript
得到jQuery detach()后节点中的某个值实现代码
2013/02/05 Javascript
关于jQuery object and DOM element
2013/04/15 Javascript
BootStrap glyphicon图标无法显示的解决方法
2016/09/06 Javascript
jQuery实现的模拟弹出窗口功能示例
2016/11/24 Javascript
JS实现数组去重方法总结(六种方法)
2017/07/14 Javascript
使用Bootrap和Vue实现仿百度搜索功能
2017/10/26 Javascript
原生JavaScript实现remove()和recover()功能示例
2018/07/24 Javascript
vue--点击当前增加class,其他删除class的方法
2018/09/15 Javascript
Node绑定全局TraceID的实现方法
2019/11/14 Javascript
ant-design-vue 快速避坑指南(推荐)
2020/01/21 Javascript
Vue关于组件化开发知识点详解
2020/05/13 Javascript
Python使用urllib2获取网络资源实例讲解
2013/12/02 Python
使用Python编写一个简单的tic-tac-toe游戏的教程
2015/04/16 Python
python Selenium爬取内容并存储至MySQL数据库的实现代码
2017/03/16 Python
python调用自定义函数的实例操作
2019/06/26 Python
python Opencv计算图像相似度过程解析
2019/12/03 Python
PyCharm无法识别PyQt5的2种解决方法,ModuleNotFoundError: No module named 'pyqt5'
2020/02/17 Python
Python迭代器Iterable判断方法解析
2020/03/16 Python
质检部部长职责
2013/12/16 职场文书
五一手机促销方案
2014/03/08 职场文书
申论倡议书范文
2014/05/13 职场文书
领导班子整改措施
2014/10/24 职场文书
道德与公民自我评价
2015/03/09 职场文书
2015年党风建设工作总结
2015/04/29 职场文书
小学教师见习总结
2015/06/23 职场文书
班级联欢会主持词
2015/07/03 职场文书
小学生一年级(书信作文)
2019/08/13 职场文书
MATLAB 全景图切割及盒图显示的实现步骤
2021/05/14 Python