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操作SQLite简明教程
Jul 10 Python
python3实现读取chrome浏览器cookie
Jun 19 Python
Python实现句子翻译功能
Nov 14 Python
Python数据结构之顺序表的实现代码示例
Nov 15 Python
python读取几个G的csv文件方法
Jan 07 Python
Selenium元素定位的30种方式(史上最全)
May 11 Python
python支持多继承吗
Jun 19 Python
学python需要去培训机构吗
Jul 01 Python
推荐技术人员一款Python开源库(造数据神器)
Jul 08 Python
Django视图、传参和forms验证操作
Jul 15 Python
Python进行统计建模
Aug 10 Python
如何完美的建立一个python项目
Oct 09 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中文汉字验证码
2007/04/08 PHP
phpExcel导出大量数据出现内存溢出错误的解决方法
2013/02/28 PHP
div li的多行多列 无刷新分页示例代码
2013/10/16 PHP
php使用strtotime和date函数判断日期是否有效代码分享
2013/12/25 PHP
微信营销平台系统?刮刮乐的开发
2014/06/10 PHP
PHP实现GIF图片验证码
2015/11/04 PHP
php实现的双色球算法示例
2017/06/20 PHP
解决php extension 加载顺序问题
2019/08/16 PHP
在Javascript里访问SharePoint列表数据的实现方法
2011/05/22 Javascript
最好用的省市二级联动 原生js实现你值得拥有
2013/09/22 Javascript
脚本合并提升javascript性能示例
2014/02/24 Javascript
jQuery 获取/设置/删除DOM元素的属性以a元素为例
2014/05/23 Javascript
JS中使用Array函数shift和pop创建可忽略参数的例子
2014/05/28 Javascript
Javascript动态创建表格及删除行列的方法
2015/05/15 Javascript
JavaScript中setUTCFullYear()方法的使用简介
2015/06/12 Javascript
jQuery 常用代码集锦(必看篇)
2016/05/16 Javascript
javascript cookie用法基础教程(概念,设置,读取及删除)
2016/09/20 Javascript
自己封装的一个原生JS拖动方法(推荐)
2016/11/22 Javascript
JavaScript模板引擎Template.js使用详解
2016/12/15 Javascript
jQuery实现选中行变色效果(实例讲解)
2017/07/06 jQuery
微信小程序实现分页加载效果
2020/11/19 Javascript
Python模块学习 datetime介绍
2012/08/27 Python
python利用多种方式来统计词频(单词个数)
2019/05/27 Python
python 操作hive pyhs2方式
2019/12/21 Python
python selenium操作cookie的实现
2020/03/18 Python
GitHub上值得推荐的8个python 项目
2020/10/30 Python
利用canvas实现图片下载功能来实现浏览器兼容问题
2019/05/31 HTML / CSS
亚马逊墨西哥站:Amazon.com.mx
2018/08/26 全球购物
美国克罗格超市在线购物:Kroger
2019/06/21 全球购物
军训生自我鉴定范文
2013/12/27 职场文书
收款委托书
2014/10/14 职场文书
2014年会计个人工作总结
2014/11/24 职场文书
数学考试作弊检讨书300字
2015/02/16 职场文书
《金钱的魔力》教学反思
2016/02/20 职场文书
Nginx下SSL证书安装部署步骤介绍
2021/12/06 Servers
vue项目中的支付功能实现(微信支付和支付宝支付)
2022/02/18 Vue.js