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 相关文章推荐
压缩包密码破解示例分享(类似典破解)
Jan 17 Python
python正则表达式match和search用法实例
Mar 26 Python
Python打印斐波拉契数列实例
Jul 07 Python
使用Python判断质数(素数)的简单方法讲解
May 05 Python
对Python中9种生成新对象的方法总结
May 23 Python
Python3实现的爬虫爬取数据并存入mysql数据库操作示例
Jun 06 Python
Python读取txt某几列绘图的方法
Oct 14 Python
利用Python对文件夹下图片数据进行批量改名的代码实例
Feb 21 Python
解决python多行注释引发缩进错误的问题
Aug 23 Python
使用django和vue进行数据交互的方法步骤
Nov 11 Python
python+Django+pycharm+mysql 搭建首个web项目详解
Nov 29 Python
pandas 对group进行聚合的例子
Dec 27 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
url decode problem 解决方法
2011/12/26 PHP
Thinkphp关闭缓存的方法
2015/06/26 PHP
PHP 爬取网页的主要方法
2018/07/13 PHP
ExtJS中文乱码之GBK格式编码解决方案及代码
2013/01/20 Javascript
nodejs中简单实现Javascript Promise机制的实例
2014/12/06 NodeJs
jquery 表单验证之通过 class验证表单不为空
2015/11/02 Javascript
js简单判断移动端系统的方法
2016/02/25 Javascript
基于javascript制作微信聊天面板
2020/08/09 Javascript
浅谈Javascript数组(推荐)
2016/05/17 Javascript
简单实现jQuery轮播效果
2017/08/18 jQuery
Node解决简单重复问题系列之Excel内容的获取
2018/01/02 Javascript
浅谈在vue中用webpack打包之后运行文件的问题以及相关配置方法
2018/02/21 Javascript
vue列表单项展开收缩功能之this.$refs的详解
2019/05/05 Javascript
jQuery实现input[type=file]多图预览上传删除等功能
2019/08/02 jQuery
vue中更改数组中属性,在页面中不生效的解决方法
2019/10/30 Javascript
关于vue 项目中浏览器跨域的配置问题
2020/11/10 Javascript
Python连接DB2数据库
2016/08/27 Python
Python将list中的string批量转化成int/float的方法
2018/06/26 Python
用uWSGI和Nginx部署Flask项目的方法示例
2019/05/05 Python
Python 使用type来定义类的实现
2019/11/19 Python
Pytorch之保存读取模型实例
2019/12/30 Python
Jupyter Notebook输出矢量图实例
2020/04/14 Python
Python-openCV开运算实例
2020/07/05 Python
详细分析Python collections工具库
2020/07/16 Python
杭州时比特电子有限公司SQL
2013/08/22 面试题
在校生钳工实习自我鉴定
2013/09/19 职场文书
校园广播稿500字
2014/02/04 职场文书
受伤赔偿协议书
2014/09/24 职场文书
2014年结对帮扶工作总结
2014/12/17 职场文书
三八节活动主持词
2015/07/04 职场文书
2016年元旦寄语
2015/08/17 职场文书
golang中切片copy复制和等号复制的区别介绍
2021/04/27 Golang
如何正确理解python装饰器
2021/06/15 Python
详解Python为什么不用设计模式
2021/06/24 Python
使用python将HTML转换为PDF pdfkit包(wkhtmltopdf) 的使用方法
2022/04/21 Python
一篇文章带你掌握SQLite3基本用法
2022/06/14 数据库