2 高精度运算Word文件下载.docx
《2 高精度运算Word文件下载.docx》由会员分享,可在线阅读,更多相关《2 高精度运算Word文件下载.docx(8页珍藏版)》请在冰豆网上搜索。
end.
加法运算
高精度加法运算
首先,确定a和b中的最大位数x,然后依照由低位至高位的顺序进行加法运算。
在每一次运算中,a当前位加b当前位的和除以10,其整商即为进位,其余数即为和的当前位。
在进行了x位的加法后,若最高位有进位(a[x+1]<
>
0),则a的长度为x+1。
以下只列出关键程序:
numtype=array[1..255]ofword;
a,b,s:
la,lb,ls:
word;
procedureplus(vara:
varla:
b:
lb:
word);
{利用过程实现}
var
i,x:
begin
ifla>
=lb
thenx:
=la
elsex:
=lb;
=1toxdo
a[i]:
=a[i]+b[i];
a[i+1]:
=a[i+1]+a[i]div10;
=a[i]mod10;
end;
whilea[x+1]<
0do
x:
=x+1;
=x;
{最高位若有进位,则长度增加}
减法运算
高精度减法运算(a>
b)
依照由低位至高位的顺序进行减法运算。
在每一次位运算中,若出现不够减的情况,则向高位借位。
在进行了la位的减法后,若最高位为零,则a的长度减1。
numtype=array[1..255]oflongint;
a,b:
la,lb:
procedureminus(vara:
i:
ifa[i]<
b[i]
thenbegin
dec(a[i+1]);
=a[i]+10;
=a[i]-b[i];
while(a[la]=0)and(la>
1)do
dec(la);
高精度乘法运算
按照乘法规则,从a的第1位开始逐位与c(c为字节型)相乘。
在第i位乘法运算中,a的i位与c的乘积必须加上i-1位的进位,然后规整积的i-1位。
numtype=array[1..1000]ofword;
proceduremultiply(vara:
c:
a[1]:
=a[1]*c;
=2tolado
=a[i]*c;
=a[i]+a[i-1]div10;
a[i-1]:
=a[i-1]mod10;
whilea[la]>
=10do
inc(la);
a[la]:
=a[la-1]div10;
a[la-1]:
=a[la-1]mod10;
扩大进制数改善高精度运算效率
用整数数组每一个元素表示一个十进制整数的方法存在的缺点是:
如果十进制的位数很多,则对应的数组的长度会很长,并增加了高精度计算的时间。
如果用一个元素记录2位数字、3位数字或更多位数字,则数组的长度可以明显缩小,但是还要考虑数的取值范围问题,必须保证程序运行过程中不越界。
在权衡了两方面的情况后得出:
用一个longint记录4位数字是最佳的方案。
那么这个数组就相当于一个10000进制的数,其中每一个元素都是10000进制下的一位数。
一、数据类型定义:
numtype=array[1..10000]oflongint;
{可以存储40000位十进制数}
a,n:
la,ln:
ansistring;
{任意长度的字符串类型}
二、整数数组的建立和输出
readln(s);
k:
fori:
=1tokdo
j:
=(k-i+4)div4;
n[j]:
=n[j]*10+ord(s[i])-48;
end;
ln:
=(k+3)div4;
当得出最后结果n后,必须按照次高位到最低位的顺序,将每一位元素由10000进制数转换成十进制数,即必须保证每个元素对应4位十进制数。
例如n[i]=0015(0<
=i<
=ln-2),对应的十进制数不能为15,否则会导致错误结果。
可以按照如下方法输出n对应的十进制数:
write(n[ln]);
=ln-1downto1do
write(n[i]div1000,(n[i]div100)mod10,(n[i]div10)mod10,n[i]mod10);
三、基本运算
两个10000进制整数的加法和减法与前面的十进制运算方法类似,只是进制变成了10000进制。
1、整数数组减1(n:
=n-1,n为整数数组)
从n[1]出发寻找第一个非零的元素,由于接受了低位的借位,因此减1,其后缀全为9999。
如果最高位为0,则n的长度减1。
j:
=1;
while(n[j]=0)doinc(j);
{寻找第一个非零的元素}
dec(n[j]);
{该位接受低位的借位,因此减1}
=1toj-1do
n[i]:
=9999;
{其后缀全为9999}
if(j=ln)and(n[j]=0)
{如果最高位为0,则n的长度减1}
thendec(ln);
2、整数数组除以整数(a:
=adivi,a为整数数组,i为整数)
按照从高位到低位的顺序,逐位相除,把余数乘进制后加到下一位继续相除。
如果最高位为0,则a的长度减1。
l:
=0;
forj:
=ladownto1do
inc(a[j],l*10000);
=a[j]modi;
a[j]:
=a[j]divi;
whilea[la]=0dodec(la);
3、两个整数数组相乘(a:
=a*n,a和n为整数数组)
按照从高位到低位的顺序,将数组a的每一个元素与n相乘。
proceduremultiply(a,b:
la,lb:
longint;
vars:
varls:
longint);
i,j:
=1tolbdo
s[i+j-1]:
=s[i+j-1]+a[i]*b[j];
=1tola+lb-1do
s[i+1]:
=s[i+1]+s[i]div10000;
s[i]:
=s[i]mod10000;
ifs[la+lb]=0
thenls:
=la+lb-1
elsels:
=la+lb;
习题与练习
一、用高精度计算出s=1!
+2!
+3!
+...+100!
。
参考答案
二、输入任意两个整数a,b(a,b均在长整型范围内),计算a/b的结果,保留100位有效数字,最后一位要求四舍五入。
三、两个高精度数相乘。
四、2k进制数(digital.pas)(NIOP2006第四题)
【问题描述】设r是个2k进制数,并满足以下条件:
(1)r至少是个2位的2k进制数。
(2)作为2k进制数,除最后一位外,r的每一位严格小于它右边相邻的那一位。
(3)将r转换为2进制数q后,则q的总位数不超过w。
在这里,正整数k(1≤k≤9)和w(k<
W≤30000)是事先给定的。
问:
满足上述条件的不同的r共有多少个?
我们再从另一角度作些解释:
设S是长度为w的01字符串(即字符串S由w个“0”或“1”组成),S对应于上述条件(3)中的q。
将S从右起划分为若干个长度为k的段,每段对应一位2k进制的数,如果S至少可分成2段,则S所对应的二进制数又可以转换为上述的2k进制数r。
例:
设k=3,w=7。
则r是个八进制数(23=8)。
由于w=7,长度为7的01字符串按3位一段分,可分为3段(即1,3,3,左边第一段只有一个二进制位),则满足条件的八进制数有:
2位数:
高位为1:
6个(即12,13,14,15,16,17),高位为2:
5个,…,高位为6:
1个(即67)。
共6+5+…+1=21个。
3位数:
高位只能是1,第2位为2:
5个(即123,124,125,126,127),第2位为3:
4个,…,第2位为6:
1个(即167)。
共5+4+…+1=15个。
所以,满足要求的r共有36个。
【输入文件】
输入文件digital.in只有1行,为两个正整数,用一个空格隔开:
kW
【输出文件】
输出文件digital.out为1行,是一个正整数,为所求的计算结果,即满足条件的不同的r的个数(用十进制数表示),要求最高位不得为0,各数字之间不得插入数字以外的其他字符(例如空格、换行符、逗号等)。
(提示:
作为结果的正整数可能很大,但不会超过200位)
【输入样例】
37
【输出样例】
36
【题目分析】
考虑一个首位为r、位数为n且除最后一位每一位严格小于右边的2k进制数,它的种数等于从2k-(r+1)个自然数中选出n-1个升序排列。
而题目所求答案等于首位为1..2wmodk-1、位数为w/k+1且符合要求的2k进制数种数,加上首位任意、位数不超过w/k不低于2的且符合要求的2k进制数种数。
(当wmodk=0时直接考虑后者即可)
因为k,W是指定的,则可以确定2k进制数r的最长位数是wdivk+1,设d=wdivk,则d位2k进制数组成的2位以上d位以下的升序排列数应该是:
这里还要比较d与的2k-1大小,必须保证d<
=2k-1。
最后考虑首位的情况,显然首位的最大二进制位数是wmodk,则最大值m=2wmodk
-1,则首位不大于m,总位数是d+1位的升序排列数应是:
这里也要比较d与的2k-1大小,必须保证d<
=2k-1-m。
两者相加即所求,因为最终的运算结果可能会很大,所以必须使用高精度运算。
【参考程序】
【NIOP满分程序】