高精度计算(二)

  • 格式:doc
  • 大小:52.50 KB
  • 文档页数:5

高精度计算(二)【例3】高精度乘法。

从键盘读入两个正整数,求它们的积。

分析:(1)、乘法运算a←a*c(a为高精度类型,c为字节型)按照乘法规则,从a的第l位开始逐位与c相乘。

在第i位乘法运算中(1≤i≤la),a的i位与c的乘积必须加上i-1位的进位(i-1位的乘积除以10的整商),然后规整积的i-l位(取i-1位的乘积对10的余数)。

procedure multiply(var a:numtype; c:byte);vari:byte;begina[1] ←a[l]*c;{第1位初始化}for i←2 to la do {逐位相乘}begina[i] ←a[i]*c;a[i] ←a[i]+a[i-l] div 10;a[i-1] ←a[i-l] mod 10end:{for}while a[1a]>=10 do {积的最高位进位}beginla←la+1;a[la] ←a[la-1] div 10;a[la-1] ←a[la-1]mod 10;end; {while}end;{multiply}(2)、乘法运算c←a*b(a,b为高精度类型,)类似加法,可以用竖式求乘法。

在做乘法运算时,同样也有进位,同时对每一位进乘法运算时,必须进行错位相加,如图3, 图4。

分析C 数组下标的变化规律,可以写出如下关系式:C i= C 'i +C ''i +…由此可见,C i跟A[i]*B[j]乘积有关,跟上次的进位有关,还跟原C i的值有关,分析下标规律,有x:= A[i]*B[j]+ x DIV 10+ C[i+j-1];C[i+j-1] := x mod 10;类似,高精度乘法的参考程序:program exam3;constmax=200;vara,b,c:array[1..max] of 0..9;n1,n2:string;lena,lenb,lenc,i,j,x:integer;beginwrite(’Input multiplier:’); readln(n1);write(’Input multiplicand:’); readln(n2);lena:=length(n1); lenb:=length(n2);for i:=1 to lena do a[lena-i+1]:=ord(n1[i])-ord(’0’);for i:=1 to lenb do b[lenb-i+1]:=ord(n2[i])-ord(’0’);for i:=1 to lena do beginx:=0;for j:=1 to lenb do begin {对乘数的每一位进行处理}x := a[i]*b[j] + x div 10 + c[i+j-1]; {当前乘积+上次乘积进位+原数}c[i+j-1] := x mod 10;end;c[i+j]:= x div 10; {进位}end;lenc:=i+j;while (c[lenc]=0) and (lenc>1) do dec(lenc);for i:=lenc downto 1 do write(c[i]);writelnend.【例4】高精度除法。

从键盘读入两个正整数,求它们的商(做整除)。

分析:做除法时,每一次上商的值都在0~9,每次求得的余数连接以后的若干位得到新的被除数,继续做除法。

因此,在做高精度除法时,要涉及到乘法运算和减法运算,还有移位处理。

当然,为了程序简洁,可以避免高精度乘法,用0~9 次循环减法取代得到商的值。

这里,我们讨论一下高精度数除以单精度数的结果,采取的方法是按位相除法。

program exam4;const max=200;var a,c:array[1..max] of 0..9;x,b:longint; n1,n2:string;lena:integer; code,i,j:integer;beginwrite(’Input dividend:’); readln(n1);write(’Input divisor:’); readln(n2);lena:=length(n1);for i:=1 to lena do a[i] := ord(n1[i]) - ord(’0’);val(n2,b,code);x:=0; {按位相除}for i:=1 to lena do beginc[i]:=(x*10+a[i]) div b;x:=(x*10+a[i]) mod b;end;j:=1;while (c[j]=0) and (j<lena) do inc(j); {去除高位的0}for i:=j to lena do write(c[i]) ;writelnend.【补充资料】改善高精度运算的效率以上接触到的高精度存储方法是用一个整型数组来表示一个很大的数,数组中的每一个数表示一位十进制数字。

但这种方法的缺点是,如果十进制数的位数很多,则对应数组的长度会很长,并增加了高精度计算的时间。

那么有什么方法可以改善高精度运算的效率呢?下面,我们给出两种方法:(1)扩大进制数(2)建立因子表一、扩大进制数我们可以考虑用一个数记录2位数字、3位数字或更多位数字。

理论上来说,数组中的每个数表示的数字越多,数组的长度就越短,程序运行的时间也就越短。

但是,我们还需考虑到计算机中的一个数的取值范围,必须保证它们在运算过程中不会越界。

在权衡了两方面的情况后得出:用一个longint记录4位数字是最佳的方案。

那么这个数组就相当于一个10000进制的数,其中每一个元素都是10000进制下的一位数。

1.数据类型typenumtype=array[O..9999]of longit: {整数数组类型,可存储40000位十进制数} vara,n:numtype; {a和n为10000进制的整数数组}st:string: {数串}la,ln:integer: {整数数组a和n的长度)2.整数数组的建立和输出当输入数串st后,我们从左而右扫描数串st,以四个数码为一组,将之对应的10000进制数存入数组n中。

具体方法如下:readln(st): {输入数串st}k←length(st); {取得数串st的长度}for i←0 to k-1 do {把st对应的整数保存到数组n中}beginj←(k-i+3)div 4-1:n[j] ←n[j]*10+ord(st[i+1])-48:end;{for}ln←(k+3)div 4;当得出最后结果以后,必须按照由次高位(n[1n-2])到最低位(n[O])的顺序,将每一位元素由lO000进制数转换成十进制数,即必须保证每个元素对应四位十进制数。

例如n[i]=0015(0≤i≤ln-2),对应的十进制数不能为15,否则会导致错误结果。

我们按照如下方法输出对应的十进制数:write(n[ln-1]); {输出结果}for i←ln-2 downto 0 dowrite(n[i]div 1000,(n[i]div 100)mod 10,(n[i]div 10)mod 10,n[i]mod 10); 【例5】求n!的精确值:问题分析:n!=1*2*3*4…*n,如10!=1*2*3*4…*10,当N稍微大一点时结果就很大了(如n=10时N!=3628800;n=20时N!=2432902008176640000);因此,求阶乘通常都要用到高精度算法。

我们用高精度算法求出每一位数,其算法如下:(1) 确定位数:n!=n*(n-1)*(n-2)*…*3*2*1根据数学知识可知n!的位数是:l=trunc((lnn+ln(n-1)+…+ln3+ln2+ln1)/ln10)+1;然后每位数占用一个数组单元,这里我们稍加改进,每个单元存放四位数,内存可节省1/4;(2) 进位处理:进位的条件是存储单元的数是否大于9999;(3) 输出处理:将各单元的数顺序输出,但若该单元不是最高位且不足四位数则需要在前面补零,凑成四位数.[参考程序:]program p12_12;const m=200;var a:array[1..m] of integer;f:real;i,j,y,c,n,k,l,t:integer;st1,st2:string;beginwrite('input a number n:');read(n);for i:=1 to n do f:=f+ln(i)/ln(10);l:=trunc(f)+1; {计算可能需要的位数}a[1]:=1;l:=1;k:=1;for i:=1 to n dobeginc:=0;while a[k]=0 do k:=k+1;for j:=k to l dobeginy:=a[j]*i+c; {该位上的数乘以i加上低位的进位}c:=y div 10000; {每四位数占用1个数组单元,c是进位}a[j]:=y mod 10000end;if c>0 then beginl:=l+1;a[l]:=c; {若有进位则数组的下标指针加1,增加一end; 个存储单元}end;write(n,'!=');for i:=l downto 1 do {输出处理}beginif i=l then write(a[i])else beginstr(a[i],st1);while length(st1)<4 dost1:='0'+st1;write(st1);end;end;writeln;end.运行结果:当n=10,10!=3628800,当n=15,15!=1307674368000【上机练习】1、计算A/B的精确值,设A,B是一般整数,计算机可接受的数,精确小数后20位。

不考虑四舍五入。

2、计算A/B的精确值,设A是高精度数(不超过100位),B是一般整数,计算机可接受的数,精确小数后100位。

不考虑四舍五入。

3、求s=1+2+3+..+n的精确值(n是一般整数)。