主题:高精度乘法
wangminrui0804
[专家分:30] 发布于 2009-12-11 22:41:00
求高精度乘法的做法,我是小学生,请用数组和字符串还有循环做,让我看得懂!
回复列表 (共7个回复)
沙发
abcwuhang [专家分:1840] 发布于 2009-12-13 12:31:00
SHOW一下分治法。。。
题目:高精度乘法。(a位高精度数*b位高精度数)
解析:大家都应该知道O(ab)的算法了吧,下面我推荐一个O(Log(ab))的算法。。。(虽然
没啥实际用处,不过理解一下对以后类似的题目也会有帮助。。
方法1:一位一位乘起来(时间系数O(ab))
方法2(重点):把a位数拆分成2个[a/2]位数,b那个也如此,比如:
1234567890 -----> 12345*10^5+67890
987654321 -----> 9876*10^5+54321
再相乘,1234567890*987654321=(12345*10^5+67890)*(9876*10^5+54321)
=12345*9876*10^10 + (12345*54321 + 9876*67890)*10^5 + 67890*54321 (A)
这样要算4次乘法(10的几次方不算,只是在结果后面加0就行了)和3次加法,时间效率仍是O(ab),
但是我们做一次这样的变换:
(12345-67890)*(9876-54321)=12345*9876 + 54321*67890 - 12345*54321 - 9876*67890 (B)
仔细对比下(A)(B)两个式子,可以发现(B)的前面两项恰为(A)的一头一尾,(B)的中间两项
就是(A)的中间两项(不计10的幂)。。
所以我们只要算3次乘法即可:12345*9876 67890*54321 (12345-67890)*(9876-54321)即可,
而(A)中间的两项可以用: 12345*9876 + 67890*54321 - (12345-67890)*(9876-54321)
就能算出。。。
经统计,若用方法2中的算,共需:3次乘法,2次减法,3次加法。这样看上去虽然多了2次减法,但是
乘法的次数少了一次,而总的时间效率里乘法的时间复杂度远大于加减法(在位数很多的情况下),
所以应高斯消元迭代可以得出用改进过的分治法,乘法时间复杂度为(log(ab)),
以上。。。。
PS:若是位数比较小用方法一和方法2的时间差不多,但是位数一旦上了七八十位后方法2的时间优点
就体现出来了。。。。。。
板凳
abcwuhang [专家分:1840] 发布于 2009-12-13 12:33:00
楼主加精吧。。。。。
琢磨了好几天才有所改进呢。。。。。
嘻嘻。。。。。。
3 楼
abcwuhang [专家分:1840] 发布于 2009-12-13 12:36:00
发一个貌似对的程序(时间紧,可能还有很多错,而且我家的FP又坏了。。。杯具ing)
program new_times;
type node=ansistring;
var st1,st2:node;
procedure easy(var x:node);
begin
while (x[1]='0') and (length(x)>1) do
delete(x,1,1);
end;
procedure swap(var x,y:node);
var z:node;
begin
z:=x;x:=y;y:=z;
end;
function minus(x,y:node):node;
forward;
function plus(x,y:node):node;
var i,j:longint;
jinwei:0..1;
z,k:node;
begin
easy(x);
easy(y);
if x='0' then exit(y);
if y='0' then exit(x);
if y[1]='-' then exit(minus(x,copy(y,2,length(y))));
if x[1]='-' then exit(minus(y,copy(x,2,length(x))));
while length(x)<length(y) do
insert('0',x,0);
while length(x)>length(y) do
insert('0',y,0);
z:='';
jinwei:=0;
for i:=length(x) downto 1 do
begin
j:=(ord(x[i])-ord('0'))+(ord(y[i])-ord('0'))+jinwei;
jinwei:=j div 10;
str(j mod 10,k);
insert(k,z,0);
end;
if jinwei>0 then insert('1',z,0);
plus:=z;
end;
function check(x:node):node;
begin
while pos('--',x)>0 do
delete(x,pos('--',x),2);
easy(x);
check:=x;
end;
function minus(x,y:node):node;
var i,j:longint;
jiewei:0..1;
z,k:node;
flag:boolean;
begin
easy(x);
easy(y);
if y='0' then exit(x);
if y[1]='-' then exit(plus(x,copy(y,2,length(y))));
if x='0' then exit(check('-'+y));
if x[1]='-' then exit(check('-'+plus(copy(x,2,length(x)),y)));
while length(x)<length(y) do
insert('0',x,0);
while length(x)>length(y) do
insert('0',y,0);
flag:=false;
if x<y then begin z:=x;x:=y;y:=z;z:='';flag:=true;end
else z:='';
jiewei:=0;
for i:=length(x) downto 1 do
begin
j:=(ord(x[i])-ord('0'))-(ord(y[i])-ord('0'))-jiewei;
if j<0 then
begin
jiewei:=1;
j:=j+10;
str(j mod 10,k);
insert(k,z,0);
end
else
begin
jiewei:=0;
str(j mod 10,k);
insert(k,z,0);
end;
end;
easy(z);
if flag then insert('-',z,0);
minus:=z;
end;
function inz(x:longint):node;
var a:node;
i:integer;
begin
a:='';
for i:=1 to x do
a:=a+'0';
inz:=a;
end;
function fenzhi(x,y:node):node;
var a1,a2,b1,b2,ans1,ans2:node;
sign:boolean;
p,q:int64;
r:longint;
begin
sign:=false;
if x[1]='-' then begin delete(x,1,1);sign:=not(sign);end;
if y[1]='-' then begin delete(y,1,1);sign:=not(sign);end;
if (length(x)<=8) and (length(y)<=8) then
begin
val(x,p,r);
val(y,q,r);
str(p*q,fenzhi);
if sign then insert('-',fenzhi,0);
fenzhi:=check(fenzhi);
easy(fenzhi);
exit(fenzhi);
end;
easy(x);
easy(y);
x:=check(x);
y:=check(y);
if x='1' then if sign then exit(check('-'+y))
else exit(y)
else if y='1' then if sign then exit(check('-'+x))
else exit(x);
if (x='0') or (y='0') then exit('0');
a1:=copy(x,1,length(x) div 2);
a2:=copy(x,length(x) div 2+1,length(x));
b1:=copy(y,1,length(y)-length(a2));
b2:=copy(y,length(y)-length(a2)+1,length(y));
ans1:=fenzhi(a1,b1);
ans2:=fenzhi(a2,b2);
fenzhi:=plus(plus(ans1+inz(length(a2)*2),plus(plus(ans1,ans2),fenzhi(minus(a1,a2),minus(b2,b1)))+inz(length(a2))),ans2);
if sign then insert('-',fenzhi,0);
fenzhi:=check(fenzhi);
easy(fenzhi);
exit(fenzhi);
end;
begin
readln(st1);
readln(st2);
if length(st1)<length(st2) then writeln(fenzhi(st1,st2))
else writeln(fenzhi(st2,st1));
end.
PS:如果楼主想要普通的LOG(AB)的高精度乘法,上网搜下把,一大把。。。。我就不写了。。
4 楼
小田甜 [专家分:3910] 发布于 2009-12-14 20:07:00
感觉二楼的方法不怎么好,因为监察是否进位犯不着每次都检查,只要保证不发生>65535的越界情况就很好啊。
5 楼
小田甜 [专家分:3910] 发布于 2009-12-14 21:04:00
我一直在用TP……
FP总觉得不靠谱……
program cheng;
const
len=1000;
type
num=array [1..len] of word;
var
a,b,c:num;
la,lb:word;
procedure readnum(var a:num;var l:word);
procedure sp(var a,b:word);
var t:word;
begin t:=a; a:=b; b:=t; end;
var
i:byte;
c:char;
begin
l:=1; read(c);
while c in [' ',#13,#10] do read(c);
a[1]:=ord(c)-48;
while not eoln do begin
read(c); inc(l); a[l]:=ord(c)-48;
end;
readln;
for i:=1 to l div 2 do
sp(a[i],a[l+1-i]);
end;
var
i,j:byte;
begin
readnum(a,la); readnum(b,lb);
fillchar(c,sizeof(c),0);
for i:=1 to la do for j:=1 to lb do
inc(c[i+j-1],a[i]*b[j]);
for i:=1 to la+lb do begin
inc(c[i+1],c[i] div 10);
c[i]:=c[i] mod 10
end;
for i:=la+lb downto 1 do if c[i]<>0 then break;
for i:=i downto 1 do write(c[i]);
writeln;
end.
6 楼
abcwuhang [专家分:1840] 发布于 2009-12-15 18:12:00
回4楼:我没有“监察进位”啊,只是用分治法做乘法而已,只是追求时间效率。。。。。
(编码量倒是挺大的)
7 楼
小田甜 [专家分:3910] 发布于 2009-12-17 12:36:00
回6楼:
分治算法的极限不就是分成每一位做乘法吗?那和n^2的复杂度有什么区别呢?为什么是nlogn呢?
我来回复