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 判断一个进程是否存在
Apr 09 Python
python 切片和range()用法说明
Mar 24 Python
详解在Python程序中使用Cookie的教程
Apr 30 Python
python 自定义异常和异常捕捉的方法
Oct 18 Python
详解Python中的正斜杠与反斜杠
Aug 09 Python
python 使用opencv 把视频分割成图片示例
Dec 12 Python
python实现百度OCR图片识别过程解析
Jan 17 Python
Python爬虫JSON及JSONPath运行原理详解
Jun 04 Python
Python计算信息熵实例
Jun 18 Python
为什么相对PHP黑python的更少
Jun 21 Python
5分钟快速掌握Python定时任务框架的实现
Jan 26 Python
python gui开发——制作抖音无水印视频下载工具(附源码)
Feb 07 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
晋城吧对DiscuzX进行的前端优化要点
2010/09/05 PHP
PHP+Mysql日期时间如何转换(UNIX时间戳和格式化日期)
2012/07/15 PHP
php fseek函数读取大文件两种方法
2016/10/12 PHP
JavaScript实际应用:innerHTMl和确认提示的使用
2006/06/22 Javascript
超越Jquery_01_isPlainObject分析与重构
2010/10/20 Javascript
JS的replace方法详细介绍
2012/11/09 Javascript
12种不宜使用的Javascript语法整理
2013/11/04 Javascript
使用js简单实现了tree树菜单
2013/11/20 Javascript
jquery获取URL中参数解决中文乱码问题的两种方法
2013/12/18 Javascript
jQuery+HTML5实现手机摇一摇换衣特效
2015/06/05 Javascript
一张Web前端的思维导图分享
2015/07/03 Javascript
js实现网页图片延时加载 提升网页打开速度
2016/01/26 Javascript
10分钟掌握XML、JSON及其解析
2020/12/06 Javascript
AngularJS实现自定义指令及指令配置项的方法
2017/11/20 Javascript
vue项目实战总结篇
2018/02/11 Javascript
浅析JS中回调函数及用法
2018/07/25 Javascript
Vue组件之单向数据流的解决方法
2018/11/10 Javascript
如何在wxml中直接写js代码(wxs)
2019/11/14 Javascript
[47:53]DOTA2上海特级锦标赛主赛事日 - 1 败者组第一轮#2COL VS Spirit
2016/03/02 DOTA
Python实现邮件的批量发送的示例代码
2018/01/23 Python
TensorFlow 模型载入方法汇总(小结)
2018/06/19 Python
python入门:这篇文章带你直接学会python
2018/09/14 Python
python 把列表转化为字符串的方法
2018/10/23 Python
python实现翻转棋游戏(othello)
2019/07/29 Python
python采集百度搜索结果带有特定URL的链接代码实例
2019/08/30 Python
numpy矩阵数值太多不能全部显示的解决
2020/05/14 Python
opencv 实现特定颜色线条提取与定位操作
2020/06/02 Python
英国领先的狗和宠物美容专家:Christies Direct
2017/04/03 全球购物
构造器Constructor是否可被override?
2013/08/06 面试题
应届大学生求职信
2013/12/01 职场文书
面试后感谢信
2014/02/01 职场文书
教师党的群众路线教育实践活动个人整改措施
2014/11/04 职场文书
拾金不昧感谢信范文
2015/01/21 职场文书
终止解除劳动合同证明书
2015/06/17 职场文书
2015年教务处干事工作总结
2015/07/22 职场文书
2019最新婚庆对联集锦!
2019/07/10 职场文书