回 帖 发 新 帖 刷新版面

主题:高精度乘法

求高精度乘法的做法,我是小学生,请用数组和字符串还有循环做,让我看得懂!

回复列表 (共7个回复)

沙发

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的时间优点
就体现出来了。。。。。。

板凳

楼主加精吧。。。。。
琢磨了好几天才有所改进呢。。。。。
嘻嘻。。。。。。

3 楼

发一个貌似对的程序(时间紧,可能还有很多错,而且我家的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 楼

感觉二楼的方法不怎么好,因为监察是否进位犯不着每次都检查,只要保证不发生>65535的越界情况就很好啊。

5 楼

我一直在用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 楼

回4楼:我没有“监察进位”啊,只是用分治法做乘法而已,只是追求时间效率。。。。。
(编码量倒是挺大的)

7 楼

回6楼:
分治算法的极限不就是分成每一位做乘法吗?那和n^2的复杂度有什么区别呢?为什么是nlogn呢?

我来回复

您尚未登录,请登录后再回复。点此登录或注册