大整数乘法

这算是分治的运用,在java中有个大数类,用着非常方便,但是在c/c++中就没有那么容易了,

一个整数最多也才2^64两个数字的加法或减法我们可以用数组模拟运算一遍,轻松搞定,但是两个数字的乘法呢,

比如给你这样两个数字:

A= 1234567898765432145673;

B=23456789463784628596936285;

现要求求出c=A*B, 好了问题来了怎么用算法实现呢,数组模拟运算效率太低了,一个n位和m位的数字相乘最少进行n*m次乘法运算,

在说如何运算前,我先说说如何减少乘法运算次数:

数学家高斯曾经说 (a1+b1*i)*(a2+b2*i)这样的两个复数,他可以用三次乘法运算计算出结果,

(a1+b1*i)*(a2+b2*i)=a1*b2 + (a1*b2 + b1*a2)*i - b1*b2 ,仔细一看这不是有4次乘法运算么,

其实他用了一个小优化,假设不是复数 (a1+b1)*(a2+b2) = a1*b2 + (a1*b2 + b1*a2)+ b1*b2

那么 (a1*b2 + b1*a2) =  (a1+b1)*(a2+b2) - a1*b2 - b1*b2 ,

所以就可以(a1+b1*i)*(a2+b2*i) =  a1*b2 + ((a1+b1)*(a2+b2) - a1*b2 - b1*b2) *i -b1*b2 ;三次乘法,got;

说了这么多这对我们做大数的运算有什么作用呢:

是这样的对于两个大数相乘我们肯定是采用分治的方法

数字A= A1 * 10^(n/2) + A2;

B=B1 * 10^(n/2) + B2; (当两个数字不一样长时在断的前面补0)

==>>  A*B = A1 * B1 * 10^n  +( A1* B2 + A2*B1 ) * 10^(n/2)  + A2*B2

分治的思想是:

getans(A, B)

if (  A.length   == 1  and   B.length == 1 )

return A*B;

else

return getans(A1, B1)*10^n  + (getans(A1, B1)  +  getans(A1, B2) )*  10^(n/2) + getans(B1, B2);

看样子并不难的样子但是我么来算算时间复杂度,还是以乘法作为基本操作(以加法作为基本操作求出结果和乘法一样):

O(1) = 1;

O(n) = 4O(n/2);

推到过程就不写了,但是最后算出来平均时间复杂度是O(n^2),和直接用数组模拟运算的复杂度是一样的,花这么大的力气写个66的代码并不6,

所以就优化,就用高斯的办法来优化,虽然加法次数增加了,但是最终结果是怎样的呢,推到一地啊就知道了:

换一个姿势后就有了:

数字A= A1 * 10^(n/2) + A2;

B=B1 * 10^(n/2) + B2; (当两个数字不一样长时在断的前面补0)

==>>  A*B = A1 * B1 * 10^n  +(  A*B  -  A1 * B1 * 10^n  - A2*B2 ) * 10^(n/2)  + A2*B2;

代码就变成下面的样子:

getans(A, B)

if (  A.length   == 1  and   B.length == 1 )

return A*B;

else

X <— getans(A1, B1)*10^n  ;

Y <— getans(A2, B2) ;

return  X +  ( getans(A,B)  - X - Y )*10^(n/2)     + Y;

在来算时间复杂度就变成了:

O(1) = 1;

O(n) = 3*O(n/2);

最后平均时间复杂度就变成了O(n * log2,3 )了这不就小于O(n^2) 了,

(平均时间复杂度的推导过程涉及到数学变换,所以没有写,这一个递推式的求法很多书山也有讲)

关于具体的代码,细节还是较多,等有空打完了在贴,欢迎大神指正

时间: 2024-10-29 15:25:09

大整数乘法的相关文章

大整数乘法python3实现

由于python具有无限精度的int类型,所以用python实现大整数乘法是没意义的,但是思想是一样的.利用的规律是:第一个数的第i位和第二个数大第j位相乘,一定累加到结果的第i+j位上,这里是从0位置开始算的.代码如下: import sys def list2str(li): while li[0]==0: del li[0] res='' for i in li: res+=str(i) return res def multi(stra,strb): aa=list(stra) bb=l

分治法解大整数乘法

在某些情况下,需要处理很大的整数,它无法在计算机中精确的表述和处理.若要精确的表示大整数,就必须使用软件的方法来实现大整数的运算.最常用的解决大整数运算的方法是使用一个二重循环,其算法时间复杂度为O(m*n)(其中m,n分别为两个大整数的长度):而选用分治方法则可以将算法时间复杂度降到O(n^(log3))(两个大整数的长度同为n).但分治方法的算法实现较为复杂,针对这个问题,本文借助标准C++实现了分治方法求解大整数乘法的算法. 下面分别介绍两种算法原理,及其实现: 1.使用二重循环控制两个数

大整数乘法问题

数组可以实现的算法很多,典型应用就是大整数相乘问题.利用的思想非常巧妙,感觉和链表实现多项式运算有异曲同工,大整数相乘主要避免计算机存储精度不够的时候.按照基本的乘法运算实现即可! 主要注意返回指针类型,和关键点k=i的技巧. /*! * \file 算法之美--大整数乘法问题.cpp * * \author ranjiewen * \date 2016/12/04 15:58 * * */ #include <iostream> using namespace std; #define SI

题目:大整数乘法、除法,楼梯走法,数组中不同数字,超过一半数字(好)

大整数乘法,可以用单个数字想乘,跟踪进位信息来处理. 大整数除法,可以先把除数增大到跟被除数相同的量级,然后累计相减.比如 555 / 3,就先把3增大到300,555能够减1次,那么结果+100,被除数变成255,依次进行. 楼梯走法:一次走一级,或者走两级.没什么难度. 数组中不同数字:如果是2n+1数组找出不同的那个数字,用异或就可以. 如果是找出超出一般数目的数字,用遍历,看到不一样的,就一起删除,这样的方式. 上网搜了一下,找出了更好的方法: 用变量记录备选数字,一个计数器记录该数字剩

使用快速傅里叶变换计算大整数乘法

我们知道,两个 N 位数字的整数的乘法,如果使用常规的算法,时间复杂度是 O(N2).然而,使用快速傅里叶变换,时间复杂度可以降低到 O(N logN loglogN). 假设我们要计算以下两个 N 位数字的乘积: a = (aN-1aN-2...a1a0)10 = aN-1x10N-1 + aN-2x10N-2 + ... + a1x101 + a0x100 b = (bN-1bN-2...b1b0)10 = bN-1x10N-1 + bN-2x10N-2 + ... + b1x101 + b

poj2389-Bull Math(大整数乘法)

一,题意: 大整数乘法模板题二,思路: 1,模拟乘法(注意"逢十进一") 2,倒序输出(注意首位0不输出) 三,步骤: 如:555 x 35 = 19425  5 5 5  5 5 5 x   3 5 x    3 5 -----------   ==>    ----------   2 7 7 5 25 25 25    + 1 6 6 5   +15 15 15 -------------  -----------------    1 9 4 2 5 15 40 40 2

大整数乘法 python实现

def recursive_multiply(x, y, n):   if n==1:     return x*y  else:    a = x/pow(10, n/2)    b = x-a*pow(10, n/2)    c = y/pow(10, n/2)   d = y-c*pow(10, n/2) ac = recursive_multiply(a, c, n/2)   bd = recursive_multiply(b, d, n/2)   p = recursive_multi

高精度计算-大整数乘法

大整数乘法 问题描述 求两个不超过 200 位的非负整数的积. 输入数据 有两行,每行是一个不超过 200 位的非负整数,没有多余的前导 0. 输出要求 一行,即相乘后的结果.结果里不能有多余的前导 0,即如果结果是 342,那么就不能 输出为 0342. 输入样例 12345678900 98765432100 输出样例 1219326311126352690000 解题思路 乘法规律,一个数的第i位和另一个数的第j位相乘,一定会累加到结果的第i+j位,结果的数组一个数组元素存2位数,最后对结

POJ 1001 解题报告 高精度大整数乘法模版

题目是POJ1001 Exponentiation  虽然是小数的幂 最终还是转化为大整数的乘法 这道题要考虑的边界情况比较多 做这道题的时候,我分析了 网上的两个解题报告,发现都有错误,说明OJ对于错误的判断还不够严厉. 对边界情况的讨论其实应该是思维严密的表现,当然这并不能表明我写的一点错误都没有,只是多多分析一下还是很有好处的. #include <iostream> #include <fstream> #include <string> #include &l

模板整理~~~~~大整数乘法

大整数乘法:概念上就是一个用int,long, long long ,double等存不了的数,长度为几百位 所以我们用字符串来存储并且从最小位开始存,然后大整数乘法也就转化成了 小学里的竖式乘法的问题. 例题: 链接:https://www.nowcoder.com/acm/contest/118/E来源:牛客网 题目描述 Kirai聊天的时候非常喜欢发"233","233"来源于猫扑表情第233号,是一张捶地大笑的表情. Kirai每当看到很好玩的消息的时候总会