1 / 11

算法之三:高精度计算

算法之三:高精度计算. 在利用计算机进行数值处理时,有时会遇到这样的问题:有些计算要求精度高,希望计算的数的位数可达几十位甚至几百位,虽然计算机的计算机精度也算较高了,但因受到硬件的限制,往往达不到实际问题所要求的精度。我们可以利用程序设计的方法去实现这样的高精度计算。. 高精度计算中需要处理好以下几个问题: ( 1 )数据的接收和存储方法 数据的接收和存储:当输入的数很长时,可采用字符串方式输入,这样可输入数位很长的数,利用字符串函数和操作运算,将每一位数取出,存入数组中。另一种方法是直接用循环加数组的方法输入数据。 ( 2 )高精度数位数的确定

kara
Download Presentation

算法之三:高精度计算

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. 算法之三:高精度计算 在利用计算机进行数值处理时,有时会遇到这样的问题:有些计算要求精度高,希望计算的数的位数可达几十位甚至几百位,虽然计算机的计算机精度也算较高了,但因受到硬件的限制,往往达不到实际问题所要求的精度。我们可以利用程序设计的方法去实现这样的高精度计算。 高精度计算中需要处理好以下几个问题: (1)数据的接收和存储方法 数据的接收和存储:当输入的数很长时,可采用字符串方式输入,这样可输入数位很长的数,利用字符串函数和操作运算,将每一位数取出,存入数组中。另一种方法是直接用循环加数组的方法输入数据。 (2)高精度数位数的确定 接收时往往采用字符串,所以它的位数就等于字符串的长度。 (3)进位、借位处理 加法进位:c[i]:=a[i]+b[i]; if c[i]>=10 then begin c[i]:=c[i] mod 10; c[i+1]:=c[i+1]+1; end; 减法借位:if a[i]<b[i] then begin a[i+1]:=a[i+1]-1; a[i]:=a[i]+10; end; c[i]:=a[i]-b[i]; 乘法进位: c[i+j-1]:=a[i]*b[j]+x+c[i+j-1]; x:=c[i+j-1] mod 10; C[i+j-1]:=c[i+j-1] mod 10; (4)商和余数的求法:视被除数和除数的位数情况进行处理。

  2. 例1、高精度加法。输入两个正整数,求它们的和。 算法分析:输入两个数到两个变量中,然后用赋值语句求它们的和并输出。但是,我们知道,在pascal语言中任何数据类型都有一定的表示范围,当两个被加数很大时,上述算法显然不能求出精确解,因此我们需要寻求另一种方法。加法都采用竖式方法。 如果我们用数组a,b分别存储加数和被加数,用数组c存储结果。则上例有a[1]=6,a[2]=5,a[3]=8,b[1]=5,b[2]=5,b[3]=2。c[1]=1,c[2]=1,c[3]=1,c[4]=1,如上图所示。 因此,算法描述如下: procedure add(a,b;var c); //a,b,c都为数组,分别存储被加数、加数、结果 var i,x:integer; begin i:=1; x:=0; //x是进位 while (i<=a数组长度) or (i<=b数组长度) do begin c[i]:=a[i]+b[i]+x; //第i位相加并加上次的进位 x:=c[i] div 10; //向高位进位 c[i]:=c[i] mod 10; //存储第i位的值 i:=i+1; //位置指针变量 end; end;

  3. 读入的整数一般用字符串来存储,方法1程序如下:读入的整数一般用字符串来存储,方法1程序如下: program ex1_1; const max=200; var a,b,c:array[1..max] of 0..9; n;string; lena,lenb,lenc,i,x:integer; begin write(‘input augend:’);readln(n); //输入被加数 lena:=length; //被加数放入a数组 for i:=1 to lena do a[lena-i+1]:=ord(n[i])-ord(‘0’); write(‘input addend:’); readln(n); //输入加数 lenb:=length(n); //加数放入数组b for i:=1 to lenb do b[lenb-i+1]:=ord(n[i])-ord(‘0’); i:=1; x:=0; while (i<=lena) or (i<=lenb) do begin c[i]:=a[i]+b[i]+x; //两数相加,然后加前次进位 x:=c[i] div 10; //x是进位 c[i]:=c[i] mod 10; //保存第i位的值 i:=i+1; end; if x>0 then //处理最高进位 begin lenc:=i; c[i]:=x; end else lenc:=i-1; for i:=lenc downto 1 do write(c[i]); //输出结果 writeln; end.

  4. 方法2程序如下: program ex1_2; const n=200; var str1,str2:string; a,b:array[1..n] of integer; k,l1,l2,i,j:integer; begin write(‘input a string str1:’); readln(str1); write(‘input b string str2:’); readln(str2); l1:=length(str1); l2:=length(str2); if l1>l2 then j:=l1 else j:=l2; k:=0; {以上为输入和初始化处理} for i:=l1 downto 1 do begin k:=k+1; a[k]:=ord(str1[i])-ord(‘0); end; k:=0; for i:=l2 downto 1 do begin k:=k+1; b[k]:=ord(str2[i])-ord(‘0); end; //将两个加数分别存入A、B数组中 for i:=1 to j do begin a[i]:=a[i]+b[i]; if a[i]>10 then begin a[i]:=a[i]-10; a[i+1]:=a[i+1]+1; end; //处理两数相加时的进位问题 end; if a[j+1]=0 then j:=j-1; for i:=j+1 downto 1 do write(‘相加和:‘,a[i]); //输出相加的和 writeln; end.

  5. 例2、高精度减法。输入两个正整数,求它们的差。例2、高精度减法。输入两个正整数,求它们的差。 类似加法,可以用竖式求减法。在做减法运算时,需要注意的是:被减数必须比减数大,同时需要处理借位。 program ex2; const max=200; var a,b,c:array[1..max] of 0..9; n,n1,n2:string; lena,lenb,lenc,i:integer; begin write(‘input minuend:’);readln(n1); //输入被减数 write(‘input subtrahend:’); readln(n2); //输入减数 if (length(n1)<length(n2)) or (length(n1)=length(n2)) and (n1<n2) then begin n:=n1; n1:=n2; n2:=n; //交换处理减数与被减数 write(‘-’); //交换了减数与被减数,结果为负数 end; 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’); i:=1; while i<=lena do begin if a[i]<b[i] then //不够减,那么向高位借1当10 begin a[i]:=a[i]+10; a[i+1]:=a[i+1]-1; end; c[i]:=a[i]-b[i]; //对应位相减 i:=i+1; end; lenc:=i; while (c[lenc]=0) and (lenc>1) do dce(lenc); //最高位的0不输出 for i:=lenc downto 1 do write(c[i]); end.

  6. 例3、高精度乘法。输入两个正整数,求它们的积。例3、高精度乘法。输入两个正整数,求它们的积。 算法分析:类似加法,在做乘法运算时,同样也有进位,同时对每一位进行乘法运算时,必须进行错位相加 分析c数组下标的变化规律,可以写出如下关系式:ci=ci’+ci’’+……由此可见,ci跟a[i]*b[j]乘积有关,跟上次的进位有关,还跟ci的值有关,分析下标规律, 有c[i+j-1]:=a[i]*b[j]+x+c[i+j-1]; x:=c[i+j-1] div 10; c[i+j-1] :=c[i+j-1] mod 10。 如上例:i=1,j=1时,c[1+1-1]=a[1]*b[1]+x+c[1+1-1] (1)初始化时,x=0,c[1+1-1]为空,所以c[1+1-1]=c[1]=6*5=30 (2)x=c[1] div 10=30 div 10=3 (3)c[1]=c[1] mod 10= 30 mod 10=0 当i=2,j=1时,c[2+1-1]=a[2]*b[1]+x+c[2+1-1] (1)c[2]=5*5+3+0=28 (2)x=c[2] div 10=2 (3)c[2]=c[2] mod 10=8 ……

  7. program ex3; const m=200; var a,b,c:array[1..max] of 0..9; n1,n2:string; lena,lenb,lenc,i,j,x:integer; begin write(‘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 begin x:=0; //用于存放数组进位 for j:=1 to lenb do //对乘数的每一位进行处理 begin c[i+j-1]:=a[i]*b[j]+x+c[i+j-1]; //当前乘积+上次乘各进位+原数 x:=c[i+j-1] div 10; c[i+j-1]:=c[i+j-1] mod 10; end; c[i+j]:=x; //进位 lenc:=lena+lenb; while (c[lenc]=0) and (lenc>1) do dce(lenc); for i:=lenc downto 1 do write(c[i]); wirteln; end

  8. 例4、高精度除法。输入两个正整数,求它们的商(做整除)。 算法分析:做除法时,每一次商的值都在0----9,每次求得的余数连接以后的若干位得到新的被除数,继续做除法。因此,在做高精度除法时,要涉及到乘法运算和减法运算,还有移位处理。如:123456789÷45=1’2345’6789÷45=274’3484 因为 1 div 45=0 1 mod 45=1 所以取12345 div 45=274 因为 12345 mod 45=15 所以取 156789 div 45=3484 所以答案为 2743484,余数为156789 mod 45=9 方法1:program ex4; const max=200; var a,c:array[1..max] of 0..9; x,b:longint; n1,n2:string; lena,code,i,j:integer; begin write(‘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); //字符串n2转换成数值b,code参数可省略 x:=0; for i:=1 to lena do //按位相除 begin c[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]); end.

  9. 方法2:由数学知识可知:除法运算中被除数、除数和商、余数的关系是:方法2:由数学知识可知:除法运算中被除数、除数和商、余数的关系是: 新的被除数=10*余数;商=trunc(被除数/除数);余数=被除数 mod 除数。 根据这关系,程序如下: program ex4_2; const e=500; var a,d,x:array[0..e] of integer; n,m,t:integer; begin write(‘input n,m:’); readln(n,m); write(n,’/’,m,’=‘); a[0]:=n;d[0]:=n div m; x[0]:=n mod m; write(d[o],’.’); //得到整数部分的商 for t:=1 to e do begin] if x[t-1]=0 then exit; a[t]:=x[t-1]*10; //将余数扩大10倍 d[t]:=a[t] div m; write(d[t]); //计算商 x[t]:=a[t] mod m; //生成余数; end; end. 输入为 input n,m:355 113 输出为 355/113=3.14159290353982...... 小数点后有500位的数据

  10. 练习题: • 1、求n!的值,利用过程缩精度。 • 问题描述:用高精度方法,求n!的精确值(n以一般整数输入) • 输入样例:ni.in • 10 • 输出样例:ni.out • 362880 • 2、求a/b的高精度值 • 问题描述:计算a/b的精确值,设a,b以一般整数输入,计算结果精确到小数后20位。 • 样例输入:ab,in • 3 • 样例输出:ab,out • 4/3=1.333333333333333333 • 6/5=1.2 • 3、求n累加和 • 问题描述:用高精度方法,求s=1+2+3+…n的精确值(n以一般整数输入). • 输入样例:ja.in • 10 • 输出样例:ja.out • 55

  11. 4、阶段和 问题描述:已知正整数n(n<=100),设s=1!+2!+3!+…+n! 请编程实现,输入正整数n,输出计算结果s的值。 输入样例:sum.in 4 输出样例:sum.out 33 5、高精度求积(multiply.pas) 问题描述:输入两个高精度正整数m和n(m和n均小于100位),求这两个高精度的积。 输入样例:multiply.in 36 3 输出样例:multiply.out 108

More Related