分治法的應用
【演算法】
mul(a[0…n-1], b[0…n-1], n)
//計算兩個大整數
a, b
的乘積
//輸入:字元陣列(或字串)表示的兩個大整數
//輸出:以字串形式輸出的兩個大整數的乘積
if (n == 1)
return a[0] * b[0];
//高位補0,使
n成為偶數(二分需要)
if (n%2 == 0)
//進行二分
a1 = a[0, n/2]; //a
的前半部分
a0 = a[n/2, n-1]; //a
的後半部分
b1 = b[0, n/2]; //b
的前半部分
b0 = b[n/2, n-1]; //b
的後半部分
/*那麼a = a1*10^n/2 + a0 b = b1*10^n/2 + b0
利用與計算兩位數相同的方法可以得到:
c = a*b = (a1*10^n/2 + a0)*(b1*10^n/2 + b0)
= (a1*b1)10^n + (a1*b0 + a0*b1)10^n/2 + (a0*b0)
=c2*10^n + c1*10^n/2 + c0
其中,c2 = a1 * b1,
是它們前半部分的積,
c0 = a0 * b0
,是它們後半部分的積
c1 = (a1*b0 + a0*b1) = (a1 + a0) * (b1 + b0) – (c2 + c0) ----
利用已經算出來的積
(c2, c0)
,減少乘法的數量(2次
à1 次)
*/c2 = mul(a1, b1);
c0 = mul(a0, b0);
c1 = mul(a1+a0, b1+b0) – (c2 + c0);
return c2*10^n + c1*10^n/2 + c0;
【效率分析】
該演算法會做多少次位乘呢?因為
n位數的乘法需要對
n/2位數做三次乘法運算,乘法次數
m(n)
的遞推式將會是:
當n>1
時,m(n) = 3m(n/2)
,m(1) = 1
當n = 2^k
時,我們可以利用反向替換法對它求解:
m(2^k) = 3m( 2^(k-1) ) = 3^2 m( 2^(k-2)
= 3^k m(2^(k-k)) = 3^k
因為k = log2n
, m(n) = 3
log2
n= n^1.585;
【c語言實現】
#include #include #include #include //支援的大整數的位數
#define n 1000
/* @brief reverse a string
*/void reversestr(char *a, int n)}/*
@brief return the maximum of three numbers
*/int max3(int a, int b, int c)
else
return b>c?b:c;}/*
@brief caculate the difference of a, b, restore the result in c.
the three numbers are represented in the form of string
*/void substract2str(const char *a, const char *b, int n, char *c)
else
}}/*
@brief caculate the sum of a, b, restore the result in c.
the three numbers are represented in the form of string
*/void add2str(const char *a, const char *b, int n, char *c)
if (carry)
c[i] = '1';}/*
@brief return the product of two big integers a, b, which are represented in
the form of string, also the product.
*/char* mul(char *a, char *b, size_t n)
rst[2] = 0;
int temp = (a[0] - '0') * (b[0] - '0');
rst[0] = temp%10 + '0';
if (temp/10)
rst[1] = temp/10 + '0';
else
rst[1] = 0;
return rst; }
//高位補0,使n為偶數
if (n % 2 != 0)
char *a0 = a; //a 的後半部分
char *a1 = a + n/2; //a 的前半部分
char *b0 = b; //b 的後半部分
char *b1 = b + n/2; //b 的前半部分
size_t i;
//多分配一位,因為下一層次的計算中有可能要補一位
char *tp1 = (char *)calloc(n/2+2, sizeof(char));
char *tp2 = (char *)calloc(n/2+2, sizeof(char));
strncpy(tp1, a1, n/2);
strncpy(tp2, b1, n/2);
char *c2 = mul(tp1, tp2, n/2);
strncpy(tp1, a0, n/2);
strncpy(tp2, b0, n/2);
char *c0 = mul(tp1, tp2, n/2);
free(tp1); tp1 = null;
free(tp2); tp2 = null;
//兩個乘積對齊
if (strlen(c2) > strlen(c0))
else if (len > strlen(pb))
char *pd;
pd = mul(pa, pb, len);
len = strlen(pd);
free(pa); pa=null;
free(pb); pb=null;
//兩個n位數的積的位數肯定大於兩個n位數的和的位數
char *pc = (char *)calloc((len+1), sizeof(char));
if (pc == null)
add2str(c2, c0, strlen(c0), pc);
//pd pc 對齊
for (i=strlen(pc); i地位順序輸入, 則a的低位址存的是最高位的數。
比如輸入95432,那麼記憶體中會是這樣的a[0] a[1] ... a[0] : 9 5 ... 2
而我們的演算法是建立在低位址存最低位基礎上的,所以需要乙個reverse操作。
*/reversestr(a, strlen(a));
reversestr(b, strlen(b));
//對齊a和b --> 通過高位補零
if (strlen(a) > strlen(b))
{ for (i=strlen(b); i
大整數乘法
參考 http hi.baidu.com operationsystem blog item 6e45dd1af1acadf3ae51330b.html 在計算機中,長整型 long int 變數的範圍是 2147483648 至 2147483647,因此若用長整型變數做乘法運算,乘積最多不能超過...
大整數乘法
問題描述 by 計算機演算法設計與分析 王曉東 p17 通常,在分析乙個演算法的計算複雜性時,都將加法和乘法運算當作是基本運算來處理,即將執行一次加法或乘法運算所需的計算時間當作乙個僅取決於計算機硬體處理速度的常數。這個假定僅在計算機硬體能對參加運算的整數直接表示和處理時才是合理的。然而,在某些情況...
大整數乘法。
include using namespace std int multi int num1,int size1,int num2,int size2 int size size1 size2 int ret new int size int i 0 for i 0 iret i 0 for i 0...