2.5 高精度运算
2.5 高精度运算
程序所处理加工的各类数据都有相应的值域限定。一旦某类型的数据超出了规定的范围,运算结果就会出错。下表列举PASCAL内部设置的几种标准类型,其中实数single、double、comp和extended为浮点类型,必须在浮点数类型,必须在程序前通过编译命令{$n+}启动浮点数运算后才可使用这些类型。
整
数
|
类型 |
值域
|
长度 (以字节为单位) |
备注 |
byte |
0…255 |
1 |
标准类型 |
|
shortint |
-128…128 |
1 |
||
snteger |
-32768…32767 |
2 |
||
word |
0…65365 |
2 |
||
longint |
-2147483648… 2147483647 |
4 |
||
实
数
|
real |
10-38…1038 |
6 |
数据处理方式 {$ n +} |
single |
1.5*10-45…3.4*1038 |
4 |
||
double |
5.0*10-324…1.7*10308 |
8 |
||
comp |
-9.2*1018…9.2*1018 |
8 |
||
extENDed |
1.9*10-4951…1.1*104932 |
10 |
但是在有些试题中,变量运算对象的数值范围是任何数据类型所无法容纳的,因此人们不得不采用数串形式,并将其转化为整数数组,其中每个元素对应一位数,由其下标顺序指明位序号。运算规则如同算术运算。由于高精度运算的结果可能使得数据长度发生增减,因此除需要用整数数组存储数据外,还需要用一个整数变量记录整数数组的元素个数,即数据的实际长度。
2.5.1 高精度加法运算
PROCEDURE add(a,b;var c); {a,b,c都为数组,a储存被加数,b储存加数,c储存结果}
VAR I,x:integer;
BEGIN
i:=1;
While (i<=a数组长度>0) or (i<=b数组长度) Do
Beign
X:=a[I]+b[I]+x div 10; {第i位相加并加上上次的进位}
C[I]:=x mod 10; {储存第i位的值}
i:=i+1; {位置指针变量}
end;
end;
通常,读入的两个整数用可用字符串来储存,程序设计如下:
CONST max=200;
Var a,b,c:array[1..max] of 0..9;
N:string;
Lena,lenb,lenb,i,x:integer;
Beign
Write(‘Input augend:’); readln(n);
Lena:=length(n);
For i:=1 to lena do a[lena-i+1]:=ord(n[i])-ord(‘0’);
Write(‘Input addend’); readln(n);
Lenb:=length(n);
For i:=1 to lenb do b[lenb-i+1]:=ord(n[i])-ord(‘0’);
i:=1;
while (I<=lena) or (i<=lenb) do
begin
x:=a[i]+b[i]+x div 10;
c[i]:=x mod 10 ;
i:=i+1;
end;
if x>=10 then begin lenc:=i;c[i]:=1 end
else lenc:=i-1;
for i:=lenc downto 1 do write(c[i]);
writeln;
end.
2.5.2 高精度减法运算
分析:类似加法,可以用竖式求减法。在做减法运算时,需要注意的是:被减数必须比减数大,同时需要处理借位。因此可以写出如下关系式可以写出如下关系式:
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]
参考程序
CONST max=200;
Var a,b,c:array[1..max]of 0..9;
n,n1,n2:string;
lena,lenb,lenc,I,x: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(‘-‘) {n1<n2,结果为负数}
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) or (I<=lenb) do
Begin
x:=a[I]-b[I]+10+x ; {不考虑大小问题,先往高位借10}
c[I]:=x mod 10 ; {保存第I位的值}
x:=x div 10-1; {将高位借到的1减去}
I:=I+1;
End;
Lenc:=I;
While (c[lenc]=0)and (lenc>1) do dec(lenc); {最高位的0不输出}
For I:=lenc downto 1 do write(c[I]);
Writeln;
End.
2.5.3高精度乘法运算
分析:类似加法,可以用竖式求乘法。在做乘法运算时,同样也有进位,同时对每一位进行乘法运算时,必须进行错位相加。
分析C数组下标的变化规律,可以写出如下关系式:
由此可见,C跟A[i]*B[i]乘积有关,跟上次的进位有关,还跟C的位置有关,分析下标规律,有
x:=A[i]*B[i]+x div 10 + C[I+j-1];
C[I+j-1]:=x mod 10;
const max=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 nultiplicand:');readln(n2);
lena:=length(n1);lenb:=length(n2);
for i:=1 to lena do val(n1[i],a[lena-i+1]);
for i:=1 to lenb do val(n2[i],b[lenb-i+1]);
for i:=1 to lena do
begin
x:=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]);
writeln;
end.
2.5.4高精度除法运算;
分析:做除法时,每次上商的值都在0~9,每次求得的余数连接以后的若干位得到新的被除数,继续做除法。因此,在做高精度除法时,要涉及到乘法和减法运算,还有移位处理。当然,为了程序简洁,可以避免高精度乘法,用0~9次减法取代得到商的值。这里,我们讨论一下高精度数除以单精度数的结果,采取的方法是按位相除法。
〔参考程序〕:
program aa;
const max=1000;
var a,c:array[1..max] of 0..9;
p,z,q,y,x,b:longint;
n1,n2:string;
lena:integer;
code,i,j:integer;
begin
readln(n1);
readln(n2);
lena:=length(n1);
for i:=1 to lena do
a[i]:=ord(n1[i])-ord('0');
val(n2,b,code); val(n1,y,code);
x:=0; z:=y div b; q:=1;i:=1;
while (y div b)<1 do
begin
q:=i; i:=i+1; y:=y*10;
end;
for i:=1 to lena do
begin
c[i]:=(x*10+a[i]) div b;
x:=(x*10+a[i]) mod b;
end;
for j:= q to 20 do
begin
c[j]:=(x*10) div b;
x:=(x*10) mod b;
end;
j:=1;
while (c[j]=0) and (j<lena) do inc(j);
i:=1;
if z<1 then write(0,'.',c[j])
else write(z,'.',c[j]);
for i:=2 to 20 do write(c[i]);
writeln;
end.
高精度实数的除法
一、试 题
编程求解两个高精度正实数的除法。要求精确至小数点后20后,若20位内有循环节,
请标出。
二、算法分析
此题的关键不在于如何进行除法, 而在于如何使商精确至小数点后20位。 turbo.
Pascal的real类型只能提供11位十进制数的精度,不可能满足其精度要求。因此,必须像
§2.2高精度实数的减法一样,采用字符串来表示实数,并实现高精度的除法运算。
一、运算前的准备
首先,我们分别计算出被除数串中‘.’后的字符个数J(被除数的小数位数)和除数
串中‘.’后的字符个数K(除数的小数位数)。根据‘被除数和除数同乘(除)一个数,
商不变’的法则,分别在两串的尾部添max(J,K)个‘.’(即被除数和除数同乘10max(J,K)
)使得被除数和除数转换为整数。
若除数为‘0’串,则失败退出。因为0不能被任何数除。
由于除法是从被除数的高位除起,除数有几位,被除数也要看几位,因此我们在运算前
就设法使被除数的位数大于除数的位数:
若被除数的串长大于等于除数的串长,则被除数的串首添一个‘0’;
若被除数的串长小于除数的串长,则被除数的串首添若干个‘0’,使其串长比除数的
串长多出一个字符;
例如:0.1÷0.003
设 被除数串N1='0.1'; {小数位个数J=1}
除数串N2='0.003'; {小数位个数K=3}
被除数和除数同乘以10max(J,K)(103)后
N1='100';
N2='3';
由于N1的串长大于N2的串长,因此
N1='0100';
N2='3';
二、除法运算
所谓精确至小数点后20位,无非是指(除小数点后的20位前出现循环节或除尽外)
1、商的小数部分含20位;
2、对小数点后的21位进行四舍五入;
为了保证这个精度要求,我们先在被除数串尾添21个‘0’。(相当于被除数×10
21。)两数相除后,再在商串的倒数第21个字符前添一个‘.’,(相于于商 ÷10
21,)还原商值。
N1='010000………0'
└─┬─┘
21个
我们采用试商法进行运算。设K’──除数的串长
截被除数串的第1..K’个字符作为余数。若余数值小于除数,则商的第1个字符为‘
0’,否则求出满足
C1×除数≤余数<(C1+1)×除数
的C1,C1的数符作为商的第1个字符。(余数-C1×除数)作为第1次除后的余数。然后将被
除数的下一位移至该余数尾。若余数不够减,则商的第2个字符为‘0’,否则为满足
C2×除数≤余数<(C2+1)×除数
的C2数符,第2次除后的余数=第1次除后的余数-C2×除数,这时可把被除数再下一位移
至余数上,……,这样反复进行,直至全部被除数的位都下移完为止。
21个
┌──┴──┐
00333…………… 3
3√01000………………0
009 └──┬──┘
0010 21个
0009
00010
00009
00001
……
……
……
21个
┌──┴──┐
N1除以N2后的商串为‘00333…………… 3’。
第一次除,截下被除数的前K’个字符作为余数初始值;第二次除的余数为第一次除后
的余数加上从被除数中下移的第K’+1个字符……,第i次除的余数为第i-1次除后的
余数加上从被除数中下移的第K’+i-1个字符。若被除数串中未下移的字符个数≤20,
则说明已运算至小数部分,因此,产生一个判断循环小数的问题。
两数相除判断商是不是循环小数,主要看运算至小数部分后,余数是否重复出现。
如果余数重复出现,其后所得的商和余数就会出现循环,商就必定重复出现。例如,从
N1÷N2的列竖式计算可以看出,两个重复出现余数10之间的商是3,所以
.
N1÷N2='00333'
接下来的问题是如何输出带有循环小数的商。
若进入小数运算后的第x次除的余数与进入小数运算后第y次除的余数相等,我们则在商
中循环节的前x位标上小数点;相隔小数点x位的数字上方标上‘.’、相隔小数点y 位的数
字上方标上‘.’,表明小数点后的第x位数..第y位数是循环小数;然后去除商串头部的无
用0。
小数点后第x位 小数点后第y位
│ │
↓←循环小数 → ↓
. .
00…00 XX…XX.X…X…………………XX
│ ││ ││ │
└┬┘└┬─┘└────┬───┘
去除 整数部分 小数部分
无用0
.
例如 N1÷N2='33.3'。
上述算法思想,可以通过一个chu过程来描述:
procedure chu;
begin 21个
商←' '; ┌┴┐
被除数串←被除数串+'0...0';
for i:=除数串长 to 被除数串长 do
begin
{当前余数为被除数的1..i位}
if 被除数长度-i≤20(运算到小数部分)
then begin
if 当前余数与进入小数运算后的某项余数相同
then begin
两个余数间的商为循环节;输出带小数的商;
halt
end {then}
else 存贮当前余数;
end;{then}
求满足
C*除数≤被除数串中1..i位对应的数值<(C+1)*除数
的C;
C数码作为商串的下一个字符;
sub←(C*除数)对应的数串;
被除数中的(i-(sub串长-1))位..i位逐位减去sub,使得被除数的前i 个数码对应当前
余数;
end; {for}
end; {chu}
三、规整商
若相除的结果未出现循环小数,则必须按如下步骤规整商:
在商的倒数21位前添入‘.’;
删去商的串首的无用‘0’;
判断当前余数是否为‘0’串:若是,则说明被除数能被除数除尽,依次删去商的串尾
的无用‘0’;若尾字符为‘.’则为整除,删去‘.’;若商串为‘ ’,则原被除数为
0,商置换为‘0’;
若余数非‘0’串,说明运算至小数点后20位还未除尽。为了保证试题要求的精度,
分析商的尾数符。若大于‘4’,则前一位数进一。删去尾数符。
显然,规整后的商串正好对应问题的解。
三、程序分析
下面,我们采用逐步求精的办法给出程序的解。
┏ program chu_fa;
┃ 一、初始化
第┃ 1.1 定义与说明;
┃ begin
一┃ 1.2 init;
┣ 二、计算
层┃ 2.2 chu;
┗ 三、输出结果
3.1 show;
end. {main}
第二层
1、求精1.1─定义与说明
var
one,two : string; {被除数(余数),除数}
list : array[1..21] of string;
{list[i]─小数点后第i次相除后的余数(0≤i≤21)}
ans : string; {商}
至于函数和过程说明,则在下面逐一给出。
2、求精1.2─init的过程说明
输入被除数串和除数串,并对两串进行规整处理。
procedure init;
var i,j,k : integer;
begin
writeln('Input bei chu shu'); {输入被除数}
readln(one);
writeln('Input chu shu'); {输入除数}
readln(two);
i:=pos('.',one); {确定被除数中'.'的位置}
if i=0 then j:=0 else begin {求被除数的小数位数J并删去'.'}
j:=length(one)-i;
delete(one,i,1);
end; {else}
i:=pos('.',two); {确定除数中'.'的位置}
if i=0 then k:=0 else begin {求除数的小数位置k并删去'.'}
k:=length(two)-i;
delete(two,i,1);
end; {else}
if j>k
then for i:=1 to j-k do two:=two+'0' {被除数和除数化整(同乘10max(j,k)}
else for i:=1 to k-j do one:=one+'0';
while (length(two)>0) and (two[1]='0') do delete(two,1,1);
{去除除数前的多余0}
if two='' then begin {若除数为0,则无解退出}
writeln('no answer!');
halt;
end; {then}
while length(one)<="20" {被除数逐位下移至余数} do length(one) to i:="1" for {为满足精度要求,被除数先乘1021} one:="0" 21 {商串初始化为空} ; ans:="" string; : sub char; c integer; i,j,k,p var chu; procedure 3、求精2.1─ch的过程说明 {init} end; +one; {通过串首添零,使得被除数长度大于除数长度}>0 then begin
2.1.2 out(p,21-(length(one)-i));
{小数点后第P位..21-(被除数长度-i)位作为循环节,输出带循环小数的商 ,
并退出程序}
end {then}
else list[21-(length(one)-i)]:=copy(one,1,i);
{若list表中未有重复元素,则当前余数存入list表}
end; {then}
c:='0'; {商的当前位C初始化为0}
sub:=''; {积(C*除数)串初始化为长度与除数相等的'0'串}
for j:=1 to length(two) do sub:=sub+'0';
repeat inc(c); {求满足C*除数≤当前余数<(C+1)*除数的C}
2.1.3 add(sub,two);
2.1.4 until bigger(sub,copy(one,1,i));
dec(c);
sub:='';
for j:=1 to length(two) do sub:=sub+'0';
for j:=1 to ord(c)-ord('0') do add(sub,two);
for j:=length(sub) downto 1 do
{当前余数逐位减去(C*除数)后作为下一次除的余数}
for k:=1 to ord(sub[j])-ord('0') do
2.1.5 minus(i-(length(sub)-j));
ans:=ans+c; {C进入商的当前位}
end; {for}
end; {chu}
4、求精3.1─show的过程说明
对不带循环小数的商先规整处理,然后输出。
procedure show;
var i,j,k : integer;
begin
3.1.1 add_point; {加入小数点}
while (length(ans)>1) and (ans[2]<>'.') and (ans[1]='0')
{删去商串头部的无用0}
do delete(ans,1,1);
3.1.2 if chu_jing then begin {若除尽,则}
while (ans[length(ans)]='0') {删去商串尾部的无用0}
do delete(ans,length(ans),1);
if ans[length(ans)]='.' then delete(ans,length(ans),1);
{若商为整数,则删去商串尾部的'.'}
if ans='' {若商串空,输出商为0,否则输出规整后的结果}
then writeln('0')
else writeln(ans);
end {then}
else begin {若除不尽,则}
if ans[length(ans)]>'4'
{若小数点后第21位的值>4,则前一位值进一}
then inc(ans[length(ans)-1]);
delete(ans,length(ans),1); {删去小数点后第21位并输出商}
writeln(ans);
end; {else}
end; {show}
第三层
1、求精2.1.1─double(copy(one,1,i),21-(length(one)-i))的函数说明
function double(s:string;i:integer):integer;
{输入小数点后第i次相除的余数s。搜索list[1]..list[i-1]。若小数点后第j(1≤j≤i-1)
次相除的余数list[j]与s相同,则说明小数点后第j位..第i位为循环节,返回j;若小数点后的
i次相除的余数各不相同,则返回0}
var j,k : integer;
begin
j:=0;
repeat inc(j);
until (j>length(s)) or (s[j]<>'0');
if j>length(s) then begin {若s为'0'串,返回0}
double:=0;
exit;
end; {then}
for j:=1 to i-1 do {顺序搜索list[1]..list[i-1]}
begin
k:=1;
while (k<=i-j) and (s[k]='0') do inc(k);
if k>i-j then begin
while (k<=length(s)) and (s[k]=list[j,k-i+j]) do inc(k);
if k>length(s) then begin double:=j; exit; end; {then}
{若s[1]··s{i-J}为'0'串且s[i-J+1]··s[n]
=List[J,1]··[J,n-i+J], 则返回J}
end; {then}
end; {for}
double:=0;
end; {double}
2、求精2.1.2─out(p,21-(length(one)-i))的过程说明
procedure out(x, y:integer;p:integer);
{小数点后的第x位、第y位分别为循环节的开始和结束,由此得出(商的长度-y) 为小数点
的位置。该过程将小数点插入该位置,并在小数点后的第x位数字的上方和第y位数字的
上方标两个'.',表明两数之间为循环小数,然后输出带循环小数的商。}
var i,j,k : integer;
begin
dec(y);
k:=length(ans)-y+1; {求小数点的位置}
ans:=copy(ans,1,length(ans)-y)+'.'+copy(ans,length(ans)-y+1,y);
{在商的该位置插入小数点}
while (ans[1]='0') and (ans[2]<>'.') do begin {删去商头部的无用0}
delete(ans,1,1);
dec(k);
end;
for i:=1 to k+x-1 do write(' '); {小数点后的第x位上方加'.'}
write('.');
if x=y then begin
writeln;
end {then}
else begin
for i:=1 to y-x-1 do write(' '); {小数点后第y位上方加'.'}
writeln('.');
end; {else}
writeln(ans); {输出带循环小数的商并退出程序}
halt;
end; {out}
3、求精2.1.3──add(sub,two)的过程说明
procedure add(var s,t: string);
{输入两个长整数串s和t。在进行了s←s+t运算后返回s}
var i,j,p,k : integer;
begin
for i:=length(t) downto 1 do begin {从最低位开始逐位相加}
p:=length(s)-(length(t)-i); {求s串中与t的i位对应的位数}
for j:=1 to ord(t[i])-ord('0') do begin {对当前位进行累加运算}
k:=p;
while (k>0) and (s[k]='9') do begin {进位}
s[k]:='0';
dec(k);
end; {while}
if k=0 then begin s:='1'+s; inc(p); end
else inc(s[k]);
end; {for}
end; {for}
end; {add}
4、求精2.1.4─bigger(sub,copy)one,1,i)的函数说明
function bigger(s,t:string):boolean;
{比较两个长整数串s和t的大小。若s>t,则返回true;否则返回false}
var i : integer;
begin
while length(s)length(t) do t:='0'+t;
i:=1; {分别从两串最高位开始,逐位比较}
while (i<=length(s)) and (s[i]=t[i]) do inc(i);
if (i<=length(s)) and (s[i]>t[i])
then bigger:=true
else bigger:=false;
end; {bigger}
5、求精2.1.5─minus(i-(length(sub)-j))的过程说明
procedure minus(i:integer);
{余数的i位减1}
begin
while one[i]='0' do begin one[i]:='9'; dec(i); end; {while}
{若当前位为0,则向高位借位}
dec(one[i]);
end; {minus}
6、求精3.1.1─add_point的过程说明
在商的倒数第21位前加入小数点,还原商。
procedure add_point;
var i,j : integer;
begin
while length(ans)<=21 do ans:='0'+ans;
{通过在商的串首添零,使商的长度>21}
ans:=copy(ans,1,length(ans)-21)+'.'+copy(ans,length(ans)-20,21);
{加入小数点}
end; {add_point}
7、求精3.1.2─chu_jing的函数说明
若两数除尽,返回true,否则返回false。
function chu_jing:boolean;
var i,j : integer;
begin
i:=1; {从余数的第1个数符开始逐位分析余数值}
while (i<=length(one)) and (one[i]='0') do inc(i);
if i>length(one) then chu_jing:=true else chu_jing:=false;
{若余数为0串,则返回true,否则返回false}
end; {chu_jing}
1用高精度计算算出s=1!+2!+3!+......+n!(n<=50) 输入正整数n输出计算结果s(注意,是"高精度计算",不是用普通的整形变量进行运算.
program dfaw;
type
auu=array[1..100] of longint;
var
a,c:auu; b:longint; len1,len2,len:longint; n:integer; i:integer;
procedure sar;
begin
assign(input,'factor.in');
assign(output,'factor.out');
reset(input);
rewrite(output);
end;
function cheng(a:auu;b:longint):auu;
var
i:longint;
c:auu;
begin
a[1]:=a[1]*b;
for i:=2 to len1 do
begin
a:=a*b+a[i-1]div 10;
a[i-1]:=a[i-1] mod 10;
end;
while a[len1]>=10 do
begin
a[len1+1]:=a[len1] div 10;
a[len1]:=a[len1] mod 10;
len1:=len1+1;
end;
cheng:=a;
end;
function jia(a,b:auu):auu;
var
i,j:integer; c:auu;
begin
fillchar(c,sizeof(c),0);
if len<len1 then len:=len1;
for i:=1to len do
begin
c:=a+b;
if c>=10 then
begin
c:=c-10;
c[i+1]:=c[i+1]+1;
end;
end;
if c[len+1]>0 then len:=len+1;
jia:=c;
end;
function jiecheng(x:integer):auu;
var
i:integer; c:auu;
begin
fillchar(c,sizeof(c),0);
c[1]:=1;
for i:=2 to x do
c:=cheng(c,i);
jiecheng:=c;
end;
begin
sar;
fillchar(c,sizeof(c),0);
len1:=1; len:=1;
read(n);
for i:=1 to n do begin
c:=jia(jiecheng(i),c); len1:=1; end;
for i:=len downto 1 do write(c);
close(input);
close(output);
end.
program lzj;
var
i,j,n:integer;
a,b:array[1..100001]of integer;
begin
read(n);
a[1]:=1;
for i:=1to n do
begin
j:=1;
while a[j]<>0 do
begin
a[j]:=a[j]*i;
j:=j+1;
end;
j:=1;
while a[j]<>0 do
begin
a[j+1]:=a[j+1]+a[j]div 10;
a[j]:=a[j]mod 10;
j:=j+1;
end;
j:=1;
while a[j]<>0 do
begin
b[j]:=b[j]+a[j];
j:=j+1;
end;
j:=1;
while b[j]<>0 do
begin
b[j+1]:=b[j+1]+b[j]div 10;
b[j]:=b[j]mod 10;
j:=j+1;
end;
end;
for i:=1to j-1 do
write(b);
end.
算法——高精度加法、减法、乘法、阶乘、除法
所谓的高精度运算,是指参与运算的数(加数,减数,因子……)范围大大超出了标准数据类型(整型,实型)能表示的范围的运算。例如,求两个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[ i ])-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[ i ]+b[ i ]+y;
c[ i ]:=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[ i ]);
writeln;
4、例子:求两个数的加法
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[ i ])-48;
k1:=k1-1;
end;
k1:=k1+1;
l:=length(s2);
k2:=260;
for i:=l downto 1 do
begin
b[k2]:=ord(s2[ i ])-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[ i ]+b[ i ]+y;
c[ i ]:=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[ i ]);
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<k2 then k:=k1 else k:=k2;
y:=0;
for i:=260 downto k do
begin
x:=a[ i ]+b[ i ]+y;
c[ i ]:=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[ i ]<1000 then write('0');
if c[ i ]<100 then write('0');
if c[ i ]<10 then write('0');
write(c[ i ]);
end;
writeln;
end.
高精度算法
在一般的科学计算中,会经常算到小数点后几百位或者更多,当然也可能是几千亿几百亿的大数字.¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
一般这类数字我们统称为高精度数,高精度算法是用计算机对于超大数据的一种模拟加,减,乘,除,乘方,阶乘,开放等运算.¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
譬如一个很大的数字N >= 10^ 100, 很显然这样的数字无法在计算机中正常存储.¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
于是, 我们想到了办法,将这个数字拆开,拆成一位一位的 或者是四位四位的存储到一个数组中, 用一个数组去表示一个数字.这样这个数字就被称谓是高精度数.¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
对于高精度数,也要像平常数一样做加减乘除以及乘方的运算,于是就有了高精度算法:¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
下面提供了Pascal的高精度加法, 高精度乘以单精度, 高精度乘以高精度的代码, 其他版本请各位大牛添加进来吧!¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
Pascal代码如下(非完整); k为预定进制,加大进制以提高速度。¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
Procedure HPule(a, b: Arr; Var c:Arr); //高精度加法¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
Var¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
i: Integer;¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
Begin¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
FillChar(c, SizeOf(c), 0);¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
For i:= 1 To Maxn-1 Do Begin¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
c[i]:= c[i] + a[i] + b[i];¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
c[i + 1] := c[i] Div k;¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
c[i] := c[i] Mod k;¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
End;¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
End;¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
Procedure HPule(a: Arr; b:Integer; Var c:Arr); //高精度乘以单精度¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
Var¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
i: Integer;¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
Begin¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
FillChar(c, SizeOf(c), 0);¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
For i:= 1 To Maxn-1 Do Begin¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
c[i] := c[i] + a[i] * b;¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
c[i+1]:= c[i] Div k;¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
c[i]:= c[i] Mod k¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
End;¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
End;¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
Procedure HPule(a, b: Arr; ; Var c:Arr); //高精度乘以高精度¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
Var¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
i, j: Integer;¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
Begin¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
FillChar(c, SizeOf(c), 0);¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
For i:= 1 To Maxn Do ¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
For j := 1 To Maxn Begin¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
c[i+j-1] := c[i+j-1] + a[i] * b[j];¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
c[i+j]:= c[i+j-1] Div k;¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
c[i+j-1]:= c[i+j-1] Mod k¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
End;¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
End;¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
Ps:为了防止百度错误识别, 过程中有不少符号是全角状态输入.¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
高精度加法¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
var ¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
a,b,c:array[1..201] of 0..9;¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
n:string;¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
lena,lenb,lenc,i,x:integer;¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
begin¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
write('Input augend:'); readln(n);lena:=length(n); ¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
for i:=1 to lena do a[lena-i+1]:=ord(n)-ord('0');{加数放入a数组}¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
write('Input addend:'); readln(n); lenb:=length(n); ¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
for i:=1 to lenb do b[lenb-i+1]:=ord(n)-ord('0');{被加数放入b数组}¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
i:=1;¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
while (i<=lena) or(i<=lenb) do¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
begin¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
x := a + b + x div 10; {两数相加,然后加前次进位}¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
c := x mod 10; {保存第i位的值}¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
i := i + 1¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
end;¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
if x>=10 {处理最高进位}¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
then begin lenc:=i; c:=1 end ¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
else lenc:=i-1;¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
for i:=lenc downto 1 do write(c); writeln {输出结果}¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
end. ¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
高精度乘法(低对高)¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
const max=100; n=20;¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
var a:array[1..max]of 0..9;¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
i,j,k;x:integer;¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
begin¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
k:=1; a[k]:=1;{a=1}¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
for i:=2 to n do{a*2*3….*n} ¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
begin¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
x:=0;{进位初始化}¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
for j:=1 do k do{a=a*i}¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
begin¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
x:=x+a[j]*i; a[j]:=x mod 10;x:=x div 10¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
end;¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
while x>0 do {处理最高位的进位}¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
begin¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
k:=k+1;a[k]:=x mod 10;x:=x div 10¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
end¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
end;¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
writeln;¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
for i:=k dowento 1 write(a){输出a}¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
end.¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
高精度乘法(高对高)¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
var a,b,c:array[1..200] of 0..9;¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
n1,n2:string; lena,lenb,lenc,i,j,x:integer;¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
begin¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
write('Input multiplier:'); readln(n1);¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
rite('Input multiplicand:'); readln(n2);¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
lena:=length(n1); lenb:=length(n2);¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
for i:=1 to lena do a[lena-i+1]:=ord(n1)-ord('0');¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
for i:=1 to lenb do b[lenb-i+1]:=ord(n2)-ord('0');¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
for i:=1 to lena do ¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
begin ¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
x:=0; ¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
for j:=1 to lenb do{对乘数的每一位进行处理}¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
begin ¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
x := a*b[j]+x div 10+c;{当前乘积+上次乘积进位+原数} ¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
c:=x mod 10;¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
end;¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
c:= x div 10;{进位}¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
end;¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
lenc:=i+j;¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
while (c[lenc]=0) and (lenc>1) do dec(lenc); {最高位的0不输出}¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
for i:=lenc downto 1 do write(c); writeln¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
end. ¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
高精度除法¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
fillchar(s,sizeof(s),0);{小数部分初始化}¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
fillchar(posi,sizeof(posi),0); {小数值的位序列初始化}¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
len←0;st←0; {小数部分的指针和循环节的首指针初始化}¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
read(x,y);{读被除数和除数}¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
write(x div y);{输出整数部分}¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
x←x mod y;{计算x除以y的余数}¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
if x=0 then exit;{若x除尽y,则成功退出}¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
while len<limit do{若小数位未达到上限,则循环}¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
begin¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
inc(len);posi[x]←len;{记下当前位小数,计算下一位小数和余数}¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
x←x*10; s[len]←x div y;x←x mod y;¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
if posi[x]<>0 {若下一位余数先前出现过,则先前出现的位置为循环节的开始}¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
then begin st←posi[x]; break;end;{then}¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
if x=0 then break; {若除尽,则成功退出}¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
end;{while}¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
if len=0 ¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
then begin writeln;exit;end;{若小数部分的位数为0,则成功退出;否则输出小数点}¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
write('.');¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
if st=0 {若无循环节,则输出小数部分,否则输出循环节前的小数和循环节}¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
then for i←1 to len do write(s)¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
else begin¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
for i←1 to st-1 do write(s);¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
write('(');¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
for i←st to len do write(s);¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
write(')');¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q
end;{else}¸v¸ÚËÞßx\www.ntrj.net39Ä}‡Š%†Q