高精度加减乘除算法

  • 格式:pdf
  • 大小:103.06 KB
  • 文档页数:5

⾼精度加减乘除算法

⾼精度运算

所谓的⾼精度运算,是指参与运算的数(加数,减数,因⼦……)范围⼤⼤超出了标准数据类型(整型,实型)能表⽰的范围的运算。例如,求两个200位的数的和。这时,就要⽤到⾼精度算法了。在这⾥,我们先讨论⾼精度加法。⾼精度运算主要解决以下三个问题:

基本⽅法1、加数、减数、运算结果的输⼊和存储

运算因⼦超出了整型、实型能表⽰的范围,肯定不能直接⽤⼀个数的形式来表⽰。在Pascal中,能表⽰多个数的数据类型有两种:数组和字符串。

(1)数组:每个数组元素存储1位(在优化时,这⾥是⼀个重点!),有多少位就需要多少个数组元素;

⽤数组表⽰数的优点:每⼀位都是数的形式,可以直接加减;运算时⾮常⽅便

⽤数组表⽰数的缺点:数组不能直接输⼊;输⼊时每两位数之间必须有分隔符,不符合数值的输⼊习惯;

(2)字符串:字符串的最⼤长度是255,可以表⽰255位。

⽤字符串表⽰数的优点:能直接输⼊输出,输⼊时,每两位数之间不必分隔符,符合数值的输⼊习惯;

⽤字符串表⽰数的缺点:字符串中的每⼀位是⼀个字符,不能直接进⾏运算,必须先将它转化为数值再进⾏运算;运算时⾮常不⽅便;

(3)因此,综合以上所述,对上⾯两种数据结构取长补短:⽤字符串读⼊数据,⽤数组存储数据:var s1,s2:string;

a,b,c:array [1..260] of integer;

i,l,k1,k2:integer;

begin

write('input s1:');readln(s1);

write('input s2:');readln(s2);

{————读⼊两个数s1,s2,都是字符串类型}

l:=length(s1);{求出s1的长度,也即s1的位数;有关字符串的知识。}

k1:=260;

for i:=l downto 1 do

begin

a[k1]:=ord(s1)-48;{将字符转成数值}

k1:=k1-1;

end;

k1:=k1+1;

{————以上将s1中的字符⼀位⼀位地转成数值并存在数组a中;低位在后(从第260位开始),⾼位在前(每存完⼀位,k1减1)}

对s2的转化过程和上⾯⼀模⼀样。2、运算过程

在往下看之前,⼤家先列竖式计算35+86。注意的问题:

(1)运算顺序:两个数靠右对齐;从低位向⾼位运算;先计算低位再计算⾼位;

(2)运算规则:同⼀位的两个数相加再加上从低位来的进位,成为该位的和;这个和去掉向⾼位的进位就成为该位的值;如上例:3+8+1=12,向前⼀位进1,本位的值是2;可借助MOD、DIV运算完成这⼀步;

(3)最后⼀位的进位:如果完成两个数的相加后,进位位值不为0,则应添加⼀位;

(4)如果两个加数位数不⼀样多,则按位数多的⼀个进⾏计算;if k1>k2 then k:=k1 else k:=k2;

y:=0;

for i:=260 downto k do

begin

x:=a+b+y;

c:=x mod 10;

y:=x div 10;

end;

if y<>0 then begin k:=k-1;c[k]:=y; end;

3、结果的输出(这也是优化的⼀个重点)

按运算结果的实际位数输出for i:=k to 260 do write(c);

writeln;

求两个数的加法program sum;

var s,s1,s2:string;

a,b,c:array [1..260] of integer;

i,l,k1,k2:integer;

begin

write('input s1:');readln(s1);

write('input s2:');readln(s2);

l:=length(s1);

k1:=260;

for i:=l downto 1 do

begin

a[k1]:=ord(s1)-48;

k1:=k1-1;

end;

k1:=k1+1;

l:=length(s2);k2:=260;

for i:=l downto 1 do

begin

b[k2]:=ord(s2)-48;

k2:=k2-1;

end;

k2:=k2+1;

if k1>k2 then k:=k2 else k:=k1;

y:=0;

for i:=260 downto k do

begin

x:=a+b+y;

c:=x mod 10;

y:=x div 10;

end;

if y<>0 then begin k:=k-1;c[k]:=y;

end;

for i:=k to 260 do write(c);

writeln;

end.

优化:

以上的⽅法的有明显的缺点:

(1)浪费空间:⼀个整型变量(-32768~32767)只存放⼀位(0~9);

(2)浪费时间:⼀次加减只处理⼀位;

针对以上问题,我们做如下优化:⼀个数组元素存放四位数;(integer的最⼤范围是32767,5位的话可能导致出界)。具体⽅法:l:=length(s1);

k1:=260;

repeat

s:=copy(s1,l-3,4);

val(s,a[k1],code);

k1:=k1-1;

s1:=copy(s1,1,l-4);

l:=l-4;

until l<=0;

k1:=k1+1;⽽因为这个改进,算法要相应改变:

(1)运算时:不再逢⼗进位,⽽是逢万进位(mod 10000; div 10000);

(2)输出时:最⾼位直接输出,其余各位,要判断是否⾜够4位,不⾜部分要补0;例如:1,23,2345这样三段的数,输出时,应该是100232345⽽不是1234567。

改进后的算法:program sum;

var s1,s2:string;

a,b,c:array [1..260] of integer;

i,l,k1,k2,code:integer;

begin

write('input s1:');readln(s1);

write('input s2:');readln(s2);

l:=length(s1);

k1:=260;

repeat

s:=copy(s1,l-3,4);

val(s,a[k1],code);

k1:=k1-1;

s1:=copy(s1,1,l-4);

l:=l-4;

until l<=0;

k1:=k1+1;

l:=length(s2);

k2:=260;

repeat

s:=copy(s2,l-3,4);

val(s,b[k2],code);

k2:=k2-1;

s2:=copy(s2,1,l-4);

l:=l-4;

until l<=0;

k2:=k2+1;

if k1

y:=0;

for i:=260 downto k do

beginx:=a+b+y;

c:=x mod 10000;

y:=x div 10000;

end;

if y<>0 then begin k:=k-1;c[k]:=y;end;

write(c[k]);

for i:=k+1 to 260 do

begin

----if c<1000 then write('0');

----if c<100 then write('0');

----if c<10 then write('0');

----write(c);

end;

writeln;

end.

⾼精度减法1、和⾼精度加法相⽐,减法在差为负数时处理的细节更多⼀点:当被减数⼩于减数时,差为负数,差的绝对值是减数减去被减数;在程序实现上⽤⼀个变量来存储符号位,⽤另⼀个数组存差的绝对值。2、算法流程:

(1)读⼊被减数S1,S2(字符串);

(2)置符号位:判断被减数是否⼤于减数:⼤则将符号位置为空;⼩则将符号位置为“-”,交换减数与被减数;(3)被减数与减数处理成数值,放在数组中;

(4)运算:A、取数;

B、判断是否需要借位;

C、减,将运算结果放到差数组相应位中;

D、判断是否运算完成:是,转5;不是,转A;

(5)打印结果:符号位,第1位,循环处理第2到最后⼀位;3、细节:

▲如何判断被减数与减数的⼤⼩:字符串知识

(1)⾸先将两个字符串的位数补成⼀样(因为字符串的⽐较是从左边对齐的;两个字符串⼀样长才能真正地⽐较出⼤⼩):短的在左边补0k1:=length(s1);

k2:=length(s2);

if k1>k2 then for i:=1 to k1-k2 do s2:='0'+s2