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实现子类调用父类的方法
Nov 10 Python
Python实现运行其他程序的四种方式实例分析
Aug 17 Python
Python实现文件信息进行合并实例代码
Jan 17 Python
Python实现PS图像调整之对比度调整功能示例
Jan 26 Python
python的socket编程入门
Jan 29 Python
高效使用Python字典的清单
Apr 04 Python
Python 实现某个功能每隔一段时间被执行一次的功能方法
Oct 14 Python
python常用排序算法的实现代码
Nov 08 Python
Python csv文件的读写操作实例详解
Nov 19 Python
Python-numpy实现灰度图像的分块和合并方式
Jan 09 Python
Python Celery异步任务队列使用方法解析
Aug 10 Python
安装pyecharts1.8.0版本后导入pyecharts模块绘图时报错: “所有图表类型将在 v1.9.0 版本开始强制使用 ChartItem 进行数据项配置 ”的解决方法
Aug 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数组函数序列之each() - 获取数组当前内部指针所指向元素的键名和键值,并将指针移到下一位
2011/10/31 PHP
php网站判断用户是否是手机访问的方法
2013/11/01 PHP
php根据操作系统转换文件名大小写的方法
2014/02/24 PHP
smarty自定义函数用法示例
2016/05/20 PHP
PHP strcmp()和strcasecmp()的区别实例
2016/11/05 PHP
php求数组全排列,元素所有组合的方法总结
2017/03/14 PHP
PHP大文件分割上传 PHP分片上传
2017/08/28 PHP
浅谈PHP中如何实现Hook机制
2017/11/14 PHP
使用JavaScript的ActiveXObject对象检测应用程序是否安装的方法
2014/04/15 Javascript
json属性名为什么要双引号(个人猜测)
2014/07/31 Javascript
javascript实现获取图片大小及图片等比缩放的方法
2016/11/24 Javascript
javascript 注释代码的几种方法总结
2017/01/04 Javascript
vue实现验证码输入框组件
2017/12/14 Javascript
详解webpack之scss和postcss-loader的配置
2018/01/09 Javascript
Vue2.x中利用@font-size引入字体图标报错的解决方法
2018/09/28 Javascript
vue2 v-model/v-text 中使用过滤器的方法示例
2019/05/09 Javascript
微信小程序云开发详细教程
2019/05/16 Javascript
构建大型 Vue.js 项目的10条建议(小结)
2019/11/14 Javascript
浅谈Vuex的this.$store.commit和在Vue项目中引用公共方法
2020/07/24 Javascript
全面解析JavaScript Module模式
2020/07/24 Javascript
Element Dropdown下拉菜单的使用方法
2020/07/26 Javascript
vue 如何从单页应用改造成多页应用
2020/10/23 Javascript
[02:32]DOTA2英雄基础教程 美杜莎
2014/01/07 DOTA
python求众数问题实例
2014/09/26 Python
Python cookbook(数据结构与算法)字典相关计算问题示例
2018/02/18 Python
Python3实现腾讯云OCR识别
2018/11/27 Python
python 日志 logging模块详细解析
2020/03/31 Python
CSS3动画之流彩文字效果+图片模糊效果+边框伸展效果实现代码合集
2017/08/18 HTML / CSS
HTML5之SVG 2D入门5—颜色的表示及定义方式
2013/01/30 HTML / CSS
Html5移动端网页端适配(js+rem)
2021/02/03 HTML / CSS
信息与计算科学专业推荐信
2014/02/23 职场文书
家长写给老师的建议书
2014/03/13 职场文书
梅花魂教学反思
2014/04/25 职场文书
缅怀先烈主题班会
2015/08/14 职场文书
Windows下载并安装MySQL8.0.x 版本的完整教程
2022/04/10 MySQL
js作用域及作用域链工作引擎
2022/07/07 Javascript