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中集合的内建函数和内建方法学习教程
Aug 19 Python
Python中动态检测编码chardet的使用教程
Jul 06 Python
python 环境变量和import模块导入方法(详解)
Jul 11 Python
python使用锁访问共享变量实例解析
Feb 08 Python
python自动登录12306并自动点击验证码完成登录的实现源代码
Apr 25 Python
python3实现爬取淘宝美食代码分享
Sep 23 Python
django框架基于模板 生成 excel(xls) 文件操作示例
Jun 19 Python
Python 中pandas索引切片读取数据缺失数据处理问题
Oct 09 Python
python中matplotlib实现随鼠标滑动自动标注代码
Apr 23 Python
python轮询机制控制led实例
May 03 Python
使用python实现时间序列白噪声检验方式
Jun 03 Python
Python 居然可以在 Excel 中画画你知道吗
Feb 15 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字符串 ==比较运算符的副作用
2009/10/21 PHP
深入PHP与浏览器缓存的分析
2013/06/03 PHP
PHP文件缓存类实现代码
2015/10/26 PHP
php获得文件夹下所有文件的递归算法的简单实例
2016/11/01 PHP
实例说明js脚本语言和php脚本语言的区别
2019/04/04 PHP
jquery中的mouseleave和mouseout的区别 模仿下拉框效果
2012/02/07 Javascript
jquery.validate的使用说明介绍
2013/11/12 Javascript
js随机生成26个大小写字母
2016/02/12 Javascript
js实现商品抛物线加入购物车特效
2020/11/18 Javascript
详解Vue中使用v-for语句抛出错误的解决方案
2017/05/04 Javascript
微信小程序版翻牌小游戏
2018/01/26 Javascript
详解基于node.js的脚手架工具开发经历
2019/01/28 Javascript
详解关于element级联选择器数据回显问题
2019/02/20 Javascript
Vue+axios封装请求实现前后端分离
2020/10/23 Javascript
在antd4.0中Form使用initialValue操作
2020/11/02 Javascript
[02:44]DOTA2英雄基础教程 克林克兹
2014/01/15 DOTA
[04:51]TI10典藏宝瓶Ⅱ外观视频展示
2020/08/15 DOTA
用Python编写简单的定时器的方法
2015/05/02 Python
Python 的描述符 descriptor详解
2016/02/27 Python
Python使用迭代器捕获Generator返回值的方法
2017/04/05 Python
Python代码块批量添加Tab缩进的方法
2018/06/25 Python
Python打开文件,将list、numpy数组内容写入txt文件中的方法
2018/10/26 Python
对python使用telnet实现弱密码登录的方法详解
2019/01/26 Python
快速解决pyqt5窗体关闭后子线程不同时退出的问题
2019/06/19 Python
python之PyQt按钮右键菜单功能的实现代码
2019/08/17 Python
pytorch 模型可视化的例子
2019/08/17 Python
Python箱型图处理离群点的例子
2019/12/09 Python
一款纯css3实现的颜色渐变按钮的代码教程
2014/11/12 HTML / CSS
使用CSS3实现input多选框自定义样式的方法示例
2019/07/19 HTML / CSS
Html5实现单张、多张图片上传功能
2019/04/28 HTML / CSS
拖鞋店创业计划书
2014/01/15 职场文书
求职推荐信范文
2015/03/27 职场文书
2015年幼儿园后勤工作总结
2015/04/25 职场文书
高一数学教学反思
2016/02/18 职场文书
python周期任务调度工具Schedule使用详解
2021/11/23 Python
游戏《我的世界》澄清Xbox版暂无计划加入光追
2022/04/03 其他游戏