高精度计算的高精度减法
和高精度加法相比,减法在差为负数时处理的细节更多一点:当被减数小于减数时,差为负数,差的绝对值是减数减去被减数;在程序实现上用一个变量来存储符号位,用另一个数组存差的绝对值。
算法流程:(1).读入被减数S1,S2(字符串);
(2).置符号位:判断被减数是否大于减数:大则将符号位置为空;小则将符号位置为“- ”,交换减数与被减数;
(3).被减数与减数处理成数值,放在数组中;
(4).运算:A、取数;
B、判断是否需要借位;
C、减,将运算结果放到差数组相应位中;
D、判断是否运算完成:是,转5;不是,转A;
(5).打印结果:符号位,第1位,循环处理第2到最后一位;
细节:▲如何判断被减数与减数的大小?
如果位数一样,直接比较字符串大小;否则,位数多的大。
k1:=length(s1); k2:=length(s2);
if k1=k2 then
if s1<s2 then begin fh:='-'; s:=s1;s1:=s2; s2:=s;end
else if k1<k2 then begin fh:='-';s:=s1;s1:=s2;s2:=s;end;{s1存被减数,fh存符号}
▲将字符串处理成数值:
l:=length(s1);{求出s1的长度,也即s1的位数;有关字符串的知识。}
k1:=260;
for i:=l downto 1 do
begin
a[k1]:=ord(s1[i])-48;{将字符转成数值}
k1:=k1-1;
end;
k1:=k1+1;
▲运算(减法跟加法比较,减法退位处理跟加法进位处理不一样):
处理退位: 跟加法一样,在for语句外面先将退位清零,用被减数再减去退位,{注意:由于每一个数位不一定都得向前一位借位,所以这里退位得清零。例如,234-25,个位需借位,而十位不用} 接着,再判断,当被减数某一位不够减时,则需加上前一位退位过来的数。注意:由于这里采用优化方法,所以退一位,就等于后一位加上10000。)最后,再拿一个数组来存储两个减数的差。
jw:=0;
for i:=260 downto k1 do
begin
a[i]:=a[i]-jw;{此处jw为从刚处理的那一位上从本一位上的借位}
jw:=0; {此处jw为I 位准备向高一位的借位}
if a[i]<b[i] then
begin
jw:=1;
a[i]:=a[i]+10000;
end;
c[i]:=a[i]-b[i]
end;
▲打印结果: 先找到差的第一个非零数,如果差的所有位数都为零,就直接输出零; 如果不是,就输出符号位和差的第一位。剩下部分,打印补足零;因为优化后的高精度减法,是把每四个数位分成一段,而每一段则必须有四个数,当有一段不足四个数时,就得用0补足.(如:第一位是'1',第二位是'34',第三位是'345',第四位是'8', 则应写为'').注意:第一位不用补零,(如:第一位为'3',则写成'3').
while (c[k]=0) and (k<=260) do k:=k+1;
if k>260 then write('0')
else begin
write(fh,c[k]);{k是差的第1位;}
for i:=k+1 to 260 do
begin
if c[i]<100 then write('0');
if c[i]<10 then write('0');
write(c[i]);
end;
end;
参考程序:
program ZDloveQC;
var s1,s2,s3,s4,s:string;
a,b,c:array[1..260]of integer;
i,k1,k2,l,code,jw:longint;
fh:string;
begin
readln(s1); readln(s2);
k1:=length(s1); k2:=length(s2); fh:='';
if k1=k2 then
if s1<s2 then begin fh:='-';s:=s1; s1:=s2; s2:=s; end;
if k1<k2 then begin fh:='-';s:=s1; s1:=s2; s2:=s; end;
k1:=260;
l:=length(s1);
repeat
s3:=copy(s1,l-3,4);
val(s3,a[k1],code);
dec(k1);
s1:=copy(s1,1,l-4);
l:=l-4;
until l<=0;
inc(k1);
l:=length(s2);
k2:=260;
repeat
s4:=copy(s2,l-3,4);
val(s4,b[k2],code);
dec(k2);
s2:=copy(s2,1,l-4);
l:=l-4;
until l<=0;
inc(k2);
jw:=0;
for i:=260 downto k1 do
begin
a[i]:=a[i]-jw;
jw:=0;
if a[i]<b[i] then
begin
jw:=1;
a[i]:=a[i]+10000;
end;
c[i]:=a[i]-b[i];
end;
while (c[k1]=0)and(k1<260) do inc(k1);
if k1>260 then writeln('0')
else begin
write(fh,c[k1]);
for i:=k1+1 to 260 do
begin
if c[i]<1000 then write('0');
if c[i]<100 then write('0');
if c[i]<10 then write('0');
write(c[i]);
end;
end;
end.
C++参考程序:
#include<stdio.h>
#include<ctype.h>
#include<string.h>
#include<stdlib.h>
#include<stdbool.h>
int const n=1000;
typedef int arr[n];
int c[2*n+1]={}, i,j,k; arr a,b;void dushu(arr &s){int i=0,j,k,m;<br/> char b[400],ch;<br/> scanf(%c,&ch);<br/> while ((ch>=48)&& (ch <=57) )<br/> { i=i+1;<br/> b[i]=ch;<br/> scanf(%c,&ch);<br/> } k=0; for(j=i; j>=1; j=j-1) { k=k+1; s[k]=b[j]-48; } }void shuchu(int c[n]) { int i=n; j=0; while ((c[i]==0) && (i>1)) i--; for (j=i; j>0; j--) printf(%d,c[j]); printf(\n); } bool compare(arr &a,arr &b){ int i,j,k; for (i=n; i>0; i--) { if (a[i]>b[i]) {return true;} else if (a[i]<b[i]) {return false;}; } } void change(arr &a, arr &b) { int i,t; for(i=1; i<=n; i++) { t=a[i]; a[i]=b[i]; b[i]=t; } } void jiafa(arr a,arr b) {int i,j,k,m,s,t=0;<br/> for (i=1; i<=n+1; i++)<br/> {<br/> s=a[i]+b[i]+t; <br/> c[i]=s % 10;<br/> t=s / 10;<br/> } shuchu(c); } void jianfa(arr &a, arr &b) { int i,j,k,s; memset(c,0,2*n+1); for (i=1; i<=n; i++) { if (a[i]>=b[i]) c[i]=a[i]-b[i]; else { c[i]=a[i]-b[i]+10; a[i+1]--; } } shuchu(c); }void chengfa(arr a, arr b) { int i,j,k,m; memset(c,0,2*n+1); for (i=1; i<=n; i++) for (j=1; j<=n; j++) { m=i+j-1; c[m]=a[j]*b[i]+c[m]; c[m+1]=c[m] / 10; c[m]=c[m]% 10; } shuchu(c); } main(){ dushu(a); dushu(b); jiafa(a,b); if (!compare(a,b)) { printf(%c,'-'); change(a,b); } jianfa(a,b); chengfa(a,b); system(pause); return 0;}