1 / 31

高精度运算

高精度运算. 类型 数值范围 占字节数 Byte 0 .. 255 1 Word 0..65535 2 Shortint -128 .. 127 1

marty
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. 高精度运算

  2. 类型数值范围占字节数 Byte 0 .. 255 1 Word 0..65535 2 Shortint -128 .. 127 1 Integer -32768..32767; 2 Longint -2147483648 .. 2147483647 4 Longword 0..4294967295 4 Int64 -9223372036854775808 .. 9223372036854775807 8 QWord 0 .. 18446744073709551615 8

  3. n!=1×2×3×...×(n-1)×n (N>0) 0!=1 若用integer型数据表示阶乘,最多可到7!,用Longint类型也只能到12! 要求输入正整数n,求 n! 的精确表示 【算法分析】用数组存放结果,模拟人工计算过程,逐位去乘,注意进位情况的处理。

  4. 所谓的高精度运算,是指参与运算的数(加数,减数,因子……)范围大大超出了标准数据类型(整型,实型)能表示的范围的运算。例如,求两个200位的数的和。这时,就要用到高精度算法了

  5. 高精度运算主要解决以下三个问题 1、加数、减数、运算结果的输入和存储 运算因子超出了整型、实型能表示的范围,肯定不能直接用一个数的形式来表示。在Pascal中,能表示多个数的数 据类型有两种:数组和字符串。 (1)数组:每个数组元素存储1位(在优化时,这里是一个重点!),有多少位就需要多少个数组元素; 用数组表示数的优点:每一位都是数的形式,可以直接加减;运算时非常方便 用数组表示数的缺点:数组不能直接输入;输入时每两位数之间必须有分隔符,不符合数值的输入习惯; (2)字符串:字符串的最大长度是255,可以表示255位。 用字符串表示数的优点:能直接输入输出,输入时,每两位数之间不必分隔符,符合数值的输入习惯; 用字符串表示数的缺点:字符串中的每一位是一个字符,不能直接进行运算,必须先将它转化为数值再进行运算;运算时非常不方便

  6. 高精度运算涉及到的问题: 1、数据的输入。 2、数据的存储。 3、数据的运算:进位和借位。 4、结果的输出:小数点的位置、处理多于的0等。

  7. 一、高精度运算:加法 题目要求: 输入: 第一行:正整数a。 第二行:正整数b。已知:a和b(<10240)。 输出:a+b的值。 样例输入: 99 999 样例输出: 1098

  8. 高精度加法解决的问题: 1、数据的输入。 2、数据的存储。 3、加法运算,注意进位处理。 4、结果的输出。

  9. 1、数据的输入。 a和b(<10240) 字符串输入: Var s1,s2:string; Readln(s1); Readln(s2);

  10. 2、数据的存储。 为了计算方便,采用数组存储。 Var a,b:array[1..240] of integer; 将字符串转换为数组存储。 用a存s1,b存s2。 A[1]存个位,便于以后计算和进位处理 S1=’3 4 5 2 3 4 5’ ….a[3] a[2] a[1] len1:=length(s1); for i:= 1 to len1 do a[i]:=ord(s1[len1+1-i])-48; len2:=length(s2); for i:= 1 to len2 do b[i]:=ord(s2[len2+1-i])-48;

  11. 3、加法运算,注意进位处理。 把计算结果存到数组c中:c:array[1..241] of integer; 先计算。 …….a[3] a[2] a[1] ……b[3] b[2] b[1] + ……c[3] c[2] c[1] if len1>len2 then len:=len1 else len:=len2; for i:=1 to len do c[i]:=a[i]+b[i];{直接先计算} 计算后的c[i]可能>=10,怎样处理?

  12. 处理进位: for i:=1 to len do begin c[i+1]:=c[i+1]+c[i] div 10; c[i]:=c[i] mod 10; end; 4、结果的输出:数组c。 if c[len+1]>0 then len:=len+1; for i:=len downto 1 do write(c[i]);

  13. const maxn=240; {c=a+b,先加,然后再处理进位} var s1,s2:string; a,b:array[1..maxn] of integer; c:array[1..maxn+1] of integer; len,len1,len2,k,j,i:integer; begin readln(s1); {输入} readln(s2); len1:=length(s1); {数据的保存} for i:= 1 to len1 do a[i]:=ord(s1[len1+1-i])-48; len2:=length(s2); for i:= 1 to len2 do b[i]:=ord(s2[len2+1-i])-48; if len1>len2 then len:=len1 else len:=len2; for i:=1 to len do c[i]:=a[i]+b[i]; for i:=1 to len do begin c[i+1]:=c[i+1]+c[i] div 10; c[i]:=c[i] mod 10; end; if c[len+1]>0 then len:=len+1; for i:=len downto 1 do write(c[i]); end.

  14. 算法改进一:边计算边处理进位。 {c=a+b,边加边处理进位} const maxn=240; var s1,s2:string; a,b:array[1..maxn] of integer; c:array[1..maxn+1] of integer; len,len1,len2,k,j,i:integer; begin readln(s1); readln(s2); len1:=length(s1); for i:= 1 to len1 do a[i]:=ord(s1[len1+1-i])-48; len2:=length(s2); for i:= 1 to len2 do b[i]:=ord(s2[len2+1-i])-48; if len1>len2 then len:=len1 else len:=len2; for i:=1 to len do begin c[i+1]:=(a[i]+b[i]+c[i]) div 10; c[i]:=(a[i]+b[i]+c[i]) mod 10; end; if c[len+1]>0 then len:=len+1; for i:=len downto 1 do write(c[i]); end.

  15. 算法改进二:结果存在数组a中,不再定义多余的数组c,减少存储空间。(最好的方法:a=a+b)算法改进二:结果存在数组a中,不再定义多余的数组c,减少存储空间。(最好的方法:a=a+b) begin readln(s1); readln(s2); len1:=length(s1); len2:=length(s2); fillchar(a,sizeof(a),0); fillchar(b,sizeof(b),0); for i:=1 to len1 do a[i]:=ord(s1[len1-i+1])-48; for i:=1 to len2 do b[i]:=ord(s2[len2-i+1])-48; if len1>len2 then len:=len1 else len:=len2; for i:=1 to len do begin a[i+1]:=a[i+1]+(a[i]+b[i]) div 10; a[i]:=(a[i]+b[i]) mod 10; end; if a[len+1]>0 then len:=len+1; for i:=len downto 1 do write(a[i]); writeln; end.

  16. 高精度加法的应用 Fibonacci数列 Fibonacci数列的代表问题是由意大利著名数学家Fibonacci于1202年提出的“兔子繁殖问题”(又称“Fibonacci问题”)。   问题的提出:有雌雄一对兔子,假定过两个月后便每个月可繁殖雌雄各一的一对小兔子。问过n个月后共有多少对兔子? 已知:N<=93。 F(i):第i个月后共有的兔子对数。 F(1)=1; F(2)=1; f(3)=2; f(4)=3; f(5)=5; f(6)=8; F(i)=f(i-2)+f(i-1)

  17. {N<=93} var f:array[1..100] of qword; var n,i:integer; begin readln(n); f[1]:=1; f[2]:=1; for i:=3 to n do f[i]:=f[i-2]+f[i-1]; writeln(f[n]); end.

  18. for k:=3 to n do begin fillchar(f,sizeof(f),0); for i:=1 to len do begin f[i+1]:=(f1[i]+f2[i]+f[i]) div 10; f[i]:=(f1[i]+f2[i]+f[i]) mod 10; end; if f[len+1]>0 then len:=len+1; f1:=f2; f2:=f; end; writeln(len); for i:=len downto 1 do write(f[i]); end. N<=1000} var n,len,i,k:integer; f1,f2,f:array[1..210] of integer; begin fillchar(f1,sizeof(f1),0); fillchar(f2,sizeof(f2),0); readln(n); f1[1]:=1; F2[1]:=1; len:=1;

  19. 二、高精度减法运算 问题表述: 输入a,b(<10240)两个数,输出a-b的值。 样例2输入: 999 1000 样例2输出: -1 样例1输入: 456 409 样例1输出: 47

  20. 算法: 1、读入被减数s1; 2、读入减数s2; 3、如果s1<s2 ,那么交换s1和s2。{只需要计算s1-s2} 4、把s1存到数组a; 5、把s2存到数组b; 6、从低到高位计算a[i]=a[i]-b[i];注意借位。 7、输出数组a就是运算结果。

  21. 解决的问题: 1、输入、保存。 2、比较a和b的大小。从而确定结果的正负号 3、借位问题。 4、输出。

  22. 1、比较大小:如果s1>s2,不交换,如果s1<s2,交换s1和s2,保证后边s1-s2。1、比较大小:如果s1>s2,不交换,如果s1<s2,交换s1和s2,保证后边s1-s2。 S1<s2的条件: if (length(s1)<length(s2))or ((length(s1)=length(s2))and(s1<s2)) then begin fh:='-'; s:=s1; s1:=s2; s2:=s; end; 然后数组a存s1,b存s2。计算a=a-b

  23. 2、借位: if a[i]<b[i] then begin a[i+1]:=a[i+1]-1; a[i]:=a[i]+10; end; a[i]:=a[i]-b[i];

  24. {a=a-b} type numtype=array[1..240] of integer; var a,b:numtype; s1,s2,s:string; la,lb,k:integer; i:integer; fh:char; begin readln(s1); readln(s2); if s1=s2 then begin writeln(0);halt;end; if (length(s1)<length(s2))or ((length(s1)=length(s2))and(s1<s2)) then begin fh:='-';s:=s1;s1:=s2;s2:=s;end; la:=length(s1); lb:=length(s2); fillchar(a,sizeof(a),0); fillchar(b,sizeof(b),0);

  25. for i:=1 to la do a[i]:=ord(s1[la-i+1])-48; for i:=1 to lb do b[i]:=ord(s2[lb-i+1])-48; k:=la; for i:=1 to k do begin if a[i]<b[i] then begin a[i+1]:=a[i+1]-1; a[i]:=a[i]+10; end; a[i]:=a[i]-b[i]; end; while a[k]=0 do k:=k-1; if fh='-' then write(fh); for i:=k downto 1 do write(a[i]); writeln; END.

  26. for i:=1 to k do begin if a[i]<b[i] then begin a[i+1]:=a[i+1]-1; a[i]:=a[i]+10; end; a[i]:=a[i]-b[i]; end; while a[k]=0 do k:=k-1; for i:=k downto 1 do write(a[i]); end; BEGIN readln(s1); readln(s2); if s1=s2 then begin writeln(0);halt;end; if (length(s1)>length(s2))or ((length(s1)=length(s2))and(s1>s2)) then sub(s1,s2) else begin write('-');sub(s2,s1);end; END. {a=a-b} var a,b:array[1..240] of integer; s1,s2:string; procedure sub(x,y:string); var la,lb,k:integer; i:integer; begin la:=length(x); lb:=length(y); fillchar(a,sizeof(a),0); fillchar(b,sizeof(b),0); for i:=1 to la do a[i]:=ord(x[la-i+1])-48; for i:=1 to lb do b[i]:=ord(y[lb-i+1])-48; k:=la;

  27. 上机出现的问题: 1、数组的初始化: 数组使用前一般都要初始化: A:array[1..100,1..100] of integer; for i:=1 to 100 do for j:=1 to 100 do a[i,j]:=0; Fillchar(a,sizeof(a),0); 2、变量的使用要规范: 如:循环控制变量一般用 i 、 j 、 k,一般不要用m、n等。这样容易找错误。 3、如果求a+b,(a,b<=102000) 定义:a,b:ansistring;{长度最多2552=65025}

  28. if a[len+1]>0 then inc(len); 三、高精度乘法 1、高精度乘单精度(整数),求a*b,a<=10200,b<=108 var i,len:integer; s:string; b,m:longint; a:array[1..250] of longint; begin readln(s); {读入被乘数a} readln(b); {读入乘数b} len:=length(s); for i:=1 to len do a[i]:=ord(s[len-i+1])-48; for i:=1 to len do {每项乘b} a[i]:=a[i]*b; for i:=1 to len do {处理进位} begin a[i+1]:=a[i+1]+a[i] div 10; a[i]:=a[i] mod 10; end; for i:=len downto 1 do write(a[i]); end.{multiply} m:=a[len+1];{处理最高进位} while m<>0 do begin {处理最高位的进位} inc(len); a[len]:=m mod 10; m:=m div 10; end;

  29. 2、高精度乘高精度 var i,j,la,lb,len:integer; s1,s2:string; m:longint; a,b,c:array[1..250] of integer; begin readln(s1); la:=length(s1); for i:=1 to la do a[i]:=ord(s1[la-i+1])-48; readln(s2); lb:=length(s2); for i:=1 to lb do b[i]:=ord(s2[lb-i+1])-48; for i:=1 to la do for j:=1 to lb do c[i+j-1]:=c[i+j-1]+a[i]*b[j]; len:=la+lb; for i:=1 to len do begin c[i+1]:=c[i+1]+c[i] div 10; c[i]:=c[i] mod 10; end; while c[len]=0 do dec(len); m:=c[len]; while m>0 do begin c[len]:=m mod 10;m:=m div 10;inc(len);end; for i:=len-1 downto 1 do write(c[i

  30. 四、高精度除法 {高精度a除以单精度b} type data=array[0..300] of integer; var a,c:data; s1,s2:string; len,k:integer; i:integer; b,d:longint; procedure init; begin readln(s1); readln(b); fillchar(a,sizeof(a),0); len:=length(s1); for i:=1 to len do a[i]:=ord(s1[len-i+1])-48; end; procedure devide; {c:=a div b; d:= a mod b} var i:integer; begin fillchar(c,sizeof(c),0); d:=0; for i:=len downto 1 do begin d:=d*10+a[i]; c[i]:=d div b; d:=d mod b; end; while (len>=1) and (c[len]=0) do dec(len); for i:=len downto 2 do write(c[i]); writeln(c[1]); {writeln(d);} end; Begin init; devide; end.

  31. 上机练习: 1、求n!=1*2*3*。。。*n (n<=100) 2、求1!+2!+3!+。。。+n! (n<=100) 3、输入两个正的实数a,b,输出a+b的值。 输入:两行,第一行a,第二行b,a和b的长度均小于1000位。 输出:一行,a+b的值。 样例: 输入: 4.5 2.3 输出: 6.8

More Related