由于计算机具有运算速度快,计算精度高的特点,许多过去由人来完成的烦琐、复杂的数学计算,现在都可以由计算机来代替,人可以从计算中解放出来,做更具有创造性的工作。
计算机计算结果的精度,通常要受到计算机硬件环境的限制。例如,QB要计算的数字超过16位,计算机将按浮点形式输出;另一方面,计算机又有数的表示范围的限制,在一般的微型计算机上,实数的表示范围为l0-38 -l038。例如,在计算N!时,当N=34时计算结果就超过了这个范围,无法计算了。这是由计算机的硬件性质决定的,用户一般是无法改变的。但是,我们可以通过‖软‖的方式来解决这一困难,即通过程序设计的方法进行高精度计算。 学习重点
1、掌握高精度计算基本方法并能应用。
2、掌握高精度加法、高精度减法、高精度乘法。
3、掌握高精度除法,理解高精度除法运算中被除数、除数、商和余数之间的关系。 4、分析总结常用高精度算法特点,并能编写相应的程序。
5、在学习的过程中应强化―算法领先‖的意识,根据实际情况对高精度运算进行优化的策略与方法。 学习过程
一、高精度计算的基本方法
在计算机上进行高精度计算,首先要处理好以下几个基本问题: 【数据的接收与存储】
(1)一般采用字符串变量接收数据,然后用测量字符串长度函数确定其位数。 INPUT A$ L=LEN(A$)
(2)分离各位数位上的数
分离各数位上的数通常采用正向存储的方法。以―163848192‖为例,见下表:
A(9) A(8) A(7) A(6) A(5) A(4) A(3) A(2) A(1) 1 6 3 8 4 8 3 9 2
基本原理是A(1)存放个位上的数字,A(2)存放十位上的数字,……依此类推。
结合字符串中MID$可以实现各数位上数字的分离 FOR I= 1 TO L
A(I)=VAL(MID$(A$,L+1-I,1) NEXT I
【计算结果位数的确定】
(1)高精度加法的和的位数为两个加数中较大数的位数加1。
(2)高精度减法的差的位数为被减数和减数中较大数的位数加1。 (3)高精度乘法的积的位数为两个相乘的数的位数之和。 (4)高精度除法的商的位数按题目的要求确定结果的存储空间。
【进位处理】
(1)加法进位 A(k)=A(k)+B(k)
IF A(k)>10 THEN A(k)=A(k) - 10 :A(k+1)=A(k+1)+1
(2)乘法进位 Y = A(I) * B(I) + G G = INT(Y / 10) D(I)= Y – G * 10 或
Y = A(I) * B(I) + G D(J) = Y MOD 10 G = Y \\ 10
【减法借位的处理】
IF A(I)< B(I) THEN A(I+1)=A(I+1)-1:A(I)=A(I)+10 A(I)=A(I)- B(I)
【商与余数的求法】 A(I)= X(I-1)*10 D(I)=INT(A(I)/B) X(I)=A(I)-D(I)* B
【教法指导】
根据高精度抽象、小学生不易理解的特点,设置高精度计算的基本方法这一部分。本节以讲解高精度运算基本方法为主,通过一些直观性较强的教学方式引导学生主动参与,进而对数位分离、进位、除法中余数的处理有一个完整的认识,为下面的学习打好基础。
【做一做】输入一个高精度数―329807421572389‖,按正向存储的方法将各数位上的数分离出来放入A()数组。
【想一想】乘法进位中变量G是用来做什么用的?在做高精度乘法之前必须首先要对G进行什么设置?
二、高精度加法
【问题描述】
任意输入两个100位以内的正整数,打印输出它们的和。
【问题分析】
设要参与加法运算的两个数分别为X,Y,N=MAX(X的位数,Y的位数)。
将X,Y分别存放在数组A与数组B中,最低值(个位数)放在第一个单元内,由低位到高位连续存放。第N+1个单元是淮备用来存放加法进位的。 例如,当A=123456,B=135792468时
我们日常笔算加法的过程如下:(红色表示在当前位进行加法运算时有进位) 123456 + 135792468 --------------- 135915924
由于数B为9位,则N=9,
A(1)到A(9)的值分别为6,5,4,3,2,1,0,0,0。 B(1)到B(9)的值分别为8,6,4,2,9,7,5,3,1。 下表反映计算机进行高精度加法运算的过程 数组元
素编号 1 2 3 4 5 6 7 8 9 A() 6 5 4 3 2 1 0 0 0 B() 8 6 4 2 9 7 5 3 1 C() 4 2 9 5 1 9 5 3 1
两数相加时,从低位到高位,各位数字分别相加,若某一单元中的数值大于10,则将该单元中的数值减去l0,并将下一单元的数值加l。
【程序清单】 REM 4_1.BAS CLS
DIM A(100), B(100),C(100) INPUT X$, Y$
LX = LEN(X$): LY = LEN(Y$)
IF LX < LY THEN SWAP X$, Y$: SWAP LX, LY ‘把大的数换到前面 FOR I = 1 TO LX ‘数据分离存入数组A() A(I) = VAL(MID$(X$, LX + 1 - I, 1)) NEXT I
FOR I = 1 TO LY ‘数据分离存入数组B() B(I) = VAL(MID$(Y$, LY + 1 - I, 1)) NEXT I G = 0
FOR I = 1 TO 100 ‘做加法运算 S = A(I) + B(I) + G
C(I) = S MOD 10 ‘进位操作 G = S \\ 10 NEXT I
I = 100 ‘去掉前面多余的0 DO WHILE A(I) = 0 I = I - 1 LOOP
PRINT X$;\"+\";Y$;\"=\"; ‘输出结果 FOR J = I TO 1 STEP -1 PRINT USING \"#\"; C(J); NEXT J END
【运行示例】
输入:123456,135792468
输出:123456 + 135792468 = 135915924
【教法指导】
依据信息学奥赛辅导的特点,结合本节的学习目标以及重难点,本节建议采用主体式教学模式。建议在教学中使用自主探究法、分层练习法启发学生自主学习。通过引导学生尝试操作,让学生感到学习高精度加法并不枯燥,将教学的重难点在算法分析中加以强调,激发学生的学习积极性,使得重点突出。充分考虑学生的能力和个性差异,设置一些分层练习,通过实践领悟方法,进行有效的学习,让学生在学习过程中进行创新。
【想一想】
上面程序中将X,Y相加的和存放在C()数组中,我们还可以不同C()数组,将相加的和存放在A()或B()中,稍加思考相信你一定能做得很棒。
三、高精度减法
【问题描述】
任意输入两个100位以内的正整数A,B,打印输出A-B的差。
【问题分析】
设要参与减法运算的两个数分别为A,B(被减数为A,减数为B)。 N=MAX(A的位数,B的位数)。数组最大下标为N+1。
数据的存放方式与加法的存放方式相同,作减法运算之前,先判断被减数与减数的大小,如果被减数小于减数,用符号变量C$记下\"-\",同时交换被减数、减数的值。 对I=1到 N,重复下列步骤:
(1)若A(I)<B(I),则A(I+1)=A(I+1)-1:A(I)=A(I)+10 (2)A(I) = A(I) - B(I)
【程序清单】 REM 4_2.BAS DIM A(100), B(100)
FOR I = 0 TO 100: A(I) = 0: B(I) = 0: NEXT I INPUT A$: LA = LEN(A$) INPUT B$: LB = LEN(B$) PRINT A$; \" - \"; B$; \" = \";
IF A$=B$ THEN PRINT 0 : END ‘如果两数相等,输出0 ,程序结束
IF (LB > LA)OR(LB = LA AND B$ > A$) THEN SWAP A$, B$: SWAP LA, LB: C$ = \"-\" ‘如果减数小于被减数,用符号变量C$记下\"-\",同时交换减数、被减数的值 FOR I = 1 TO LA ‘数据分离存入数组A(),同时检测数据的正确性 X$ = MID$(A$, LA-I+1, 1) A(I) = VAL(X$) NEXT I
FOR I = 1 TO LB ‘数据分离存入数组B(),同时检测数据的正确性 X$ = MID$(B$, LB-I+1, 1) B(I) = VAL(X$) NEXT I
G = 0 ‘设置初始借位为0 FOR I = 1 TO 100
IF A(I) >= B(I) + G THEN ‘如果被减数大于等于减数+借位则进行减法操作 A(I) = A(I) - B(I) – G
G = 0 ‘借位为0
ELSE ‘如果被减数大于等于减数+借位则先借1,再做减法操作 A(I) = 10 + A(I) - B(I) – G
G = 1 ‘借位为1 END IF NEXT I I=100
DO WHILE A(I) = 0: I = I - 1: LOOP ‘去掉前面多余的0
IF C$ = \"-\" THEN PRINT \"-\"; ‘如果符号变量C$的值为\"-\",表示 结果为负数,须打印\"-\"
FOR J = I TO 1 STEP -1: PRINT USING \"#\"; A(J); : NEXT J: PRINT ‘输出结果 END
【运行示例】 输入: 123456789 87654321 输出:
123456789 – 987654321 = -864197532
【教法指导】
依据加减逆运算的特点,结合上节高精度加法的学习方法,本节建议采用对比教学模式。建议在教学中使用知识的迁移,运用对比分析法启发学生自主学习。通过引导学生尝试操作、对比分析,将减法的进位在算法分析中加以强调,激发学生的学习积极性,使得重点突出。充分考虑学生的能力和个性差异,设置一些分层练习,通过实践领悟方法,进行有效的学习,让学生在学习过程中进行创新。
【想一想】
减法运算的借位操作,能否像加法的进位操作那样去掉条件语句?
四、高精度乘法
【问题描述】
任意输入2个20位以内的正整数,打印输出它们的乘积。
【问题分析】
(1)数据接收:采用字符串输入的方式,把A,B两数当作字符串输入到计算机中,然后再利用字符串函数把字符串转化成为数字.分别存储在两个数组中.
(2)确定乘积的位数,设LA为被乘数A的位数,LB为乘数B的位数,由数学知识可知,乘积的位数最多为LA+LB,最少为LA+LB-1。所以,乘积的位数定为LA+LB。 (3)进位处理:
①乘法进位。用B数组中的每一个数去乘以A数组中的每一个数,如果乘积大于10,则有乘法进位产生,这时.可用下式进行进位处理:
X = A(I) * B(J) ‘X是A()数组中第I位数与B()数组中第J位数的乘积 Y = X \\ 10 ‘Y是进位的数 Z = X MOD 10 ‘Z是本位的数
乘积的位数是 W=I+J-1, 在后面的加法进位时,再把Y与Z存入乘积数组C()中。 ②加法进位。把Z加到乘积数组中C(W)=C(W)+Z,这时的C(W)如超过10,还要进位。 把Y与C(W)中的进位加到乘积数组中C(W+1)=C(W+1)+Y+C(W)\\10 C(W)中去掉进位后的数值是C(W)=C(W) MOD 10
弄清楚了乘法进位与加法进位,可以把他们合写成: X = A(I) * B(J): Y = X \\ 10: Z = X MOD 10 W = I + J - 1: C(W) = C(W) + Z
C(W + 1) = C(W + 1) + C(W) \\ 10 + Y: C(W) = C(W) MOD 10
【程序清单】 REM 4_3.BAS CLS INPUT A$ INPUT B$
LA = LEN(A$): LB = LEN(B$): LC = LA + LB ‘根据LA、LB的长度设定乘积位数 DIM A(LA), B(LB), C(LC)
FOR I = 1 TO LA: A(I) = 0: NEXT I FOR I = 1 TO LB: B(I) = 0: NEXT I FOR I = 1 TO LC: C(I) = 0: NEXT I
FOR I = 1 TO LA ‘数据分离存入数组A(),同时检测数据的正确性 X$ = MID$(A$, LA + 1 - I, 1) A(I) = VAL(X$) NEXT I
FOR I = 1 TO LB
X$ = MID$(B$, LB + 1 - I, 1) B(I) = VAL(X$) NEXT I
FOR I = 1 TO LA: FOR J = 1 TO LB ‘高精度乘法,先乘后加 X = A(I) * B(J): Y = X \\ 10: Z = X MOD 10 ‘两数相乘,乘法进位
W = I + J - 1: C(W) = C(W) + Z ‘乘积定位,X的本位数应加在乘积的C(W)中 C(W + 1) = C(W + 1) + C(W) \\ 10 + Y: C(W) = C(W) MOD 10 ‘加法进位 NEXT J, I
PRINT A$; \" * \"; B$; \" = \"; ‘输出结果 I = LC
DO WHILE C(I) = 0: I = I - 1: LOOP ‘去掉前面多余的0 FOR J = I TO 1 STEP -1: PRINT USING \"#\"; C(J); : NEXT J: PRINT END
【运行示例】 输入: 123456789 987654321 输出:
123456789 * 987654321 = 121932631112635269
上面的算法是常见高精度乘法的一般形式,在高精度乘法中还存在许多特殊的算法例如计算高精度N! 等。这里给出这两个问题的程序段,相信你能从其中发现更多的高精度乘法的规律。
【问题描述】
N的阶乘值问题(JSOI2004小学组复赛第3题)
阶乘是数学中的一种运算,N的阶乘表示为:N!=1*2*3*4*……*N
编写程序,根据一个给出的N,求得其阶乘中所有数字之和P。并判断P是否为素数。
【输入输出】 输入:
键盘输入一个自然数N(1<=N<=100)。 输出:
N的阶乘值的所有数字之和P,若P为素数输出―T‖,否则输出―F‖。 [样例1] 输入: 5 输出: 3□T [样例2] 输入: 20 输出: 54□F
【问题分析】
比较典型的高精度乘法运算,对数组元素的范围设置是本题的一个注意点,由于本题N最大为100,因此设置为100很显然是不够用,需要设置为200。按照模块化设计的理念,本题主要分为以下4个模块 (1)依据输入格式输入数据并进行数祖及变量的初始设定 (2)高精度乘法求N!
(3)累加A()各元素,并对和进行素数判定 (4)依据输出格式输出结果
【程序清单】(加粗部分为N!高精度乘法程序段) REM 4_4.BAS CLS INPUT N DIM A(200)
A(1) = 1 ‘0!= 1,初始设定A(1)=1 FOR I = 1 TO N ‘计算N !
G = 0 ‘每次计算阶乘前初始设定进位G=0 FOR J = 1 TO 200
T = A(J) * I + G ‘各数位上的数依次乘J并加上进位 G = T \\ 10 ‘各数位的乘积进行进位操作 A(J) = T MOD 10 ‘将本位上的数值赋值给A(J) NEXT J NEXT I
FOR J = 1 TO 200 P = P + A(J) NEXT J
FOR J = 2 TO INT(SQR(P))
IF P MOD J = 0 THEN PRINT MID$(STR$(P), 2); \" \"; \"F\": END NEXT J
PRINT MID$(STR$(P), 2); \" \"; \"T\" END END
【想一想】N!的高精度乘法运算中和被乘数相比较,乘数是一个什么样的数,做这一类的题目有什么规律?
【教法指导】
信息学奥赛的特点决定了在教学中必须―立足基本操作,渗透基础知识‖,本节从基本的高精度乘法出发,通过乘法进位的算法分析引导学生由易到难解决问题,进而深入探究高精度n!。在教学过程中采用演示法、迁移法,以期达到教学效果的最优化。
【练一练】
印度国王的棋盘。有一个数学家发明了一种棋盘献给了印度国王,数学家看国王非常欢喜,就向国王提出了奖赏的要求:在棋盘的第一格放一粒米,第二格放二粒米,第三格放四粒米,第四格放八粒米,.....也就是说每一格都放进了比前一格多一倍的米。国王认为这简直不值一提,就毫不犹豫的答应了。谁知结果
却让国王大吃一惊,当放到第64格时,就已经一共用了18446744073709551615粒米。输入N(1<=N<=100),输出第N格有多少粒米。
五、高精度除法
【问题描述】
高精度除法。任意输入一个高精度数A和单精度数B,计算A/B的商以及余数。
【问题分析】
在除法运算中,A/B的精确值有两种情况:
(1)A能被B整除.A/B就是它们的精确值,没有余数。 (2)A不能被B整除,对余数要进行特殊处理. 首先观察一个具体的例子。
98765432100123456789 / 87654321 = 1126760563237 …… 6659712
1126760563237 -----------------------
87654321 ) 98765432100123456789 87654321 ----------------------- 111111111 87654321 ----------------------- 234567900 175308642 ----------------------- 592592580 525925926 ----------------------- 666666541 613580247 ----------------------- 530862942 525925926 ----------------------- 493701634 438271605 ----------------------- 554300295 525925926 ----------------------- 283743696 262962963
----------------------- 207807337 175308642 ----------------------- 324986958 262962963 ----------------------- 620239959 613580247 ----------------------- 6659712
通过观察,我们可以看出,在作除法运算时,有一个不变的量和三个变化的量.一个不变量是除数.三个变化着的量中一个是被除数,一个是商,一个是余数.在做除法时,每次都是用被除数减去商与除数的乘积,若所得的余数不为零,则将其扩大10倍后再次作为被除数。继续试除,直到余数等于零或达到所要求的精度为止。
从上面的分析中,我们可以清楚地看出: A(N) = 10 * X(N-1) D(N) = INT(A(N)/B) X(N) = A(N)一D(N) * B
这样以来高精度除法问题就迎刃而解了。
【程序清单】
REM 4_5.BAS CLS
DIM B AS LONG DIM Y AS LONG
INPUT \"Input A large number =\";A$ LA=LEN(A$) ‘计算A的位数 INPUT \"Input B number =\";B$
LB=LEN(B$) : B=VAL(B$) ‘计算B的位数
DIM A(LA),D(LA+1-LB) ‘设定A()为被除数,D()为商,商的位数为LA+1-LB PRINT A$;\" / \";B$;\" = \";
FOR I=1 TO LA ‘将A各数位上的数分离,并判错 X$=MID$(A$,LA+1-I,1) A(I)=VAL(X$) NEXT I
Y=0 ‘依据B的位数,首先选取A的前LB-1位,为除法做准备 IF LB>1 THEN
FOR J=LA TO LA-LB+2 STEP -1 Y=Y*10+A(J) NEXT J
END IF
FOR K=LA+1-LB TO 1 STEP -1 ‘高精度除法 Y=Y*10+A(K) ‘余数扩大10位加本位上的数 D(K)=Y\\B ‘除法运算 Y=Y MOD B ‘求余数 NEXT K
K=LA+1-LB ‘去掉前面多余的0 WHILE D(K)=0 : K=K-1 : WEND
FOR I=K TO 1 STEP -1 ‘输出结果 PRINT USING \"#\";D(I); NEXT I
IF Y>0 THEN PRINT \" ......\";Y ELSE PRINT ‘依据Y的值选择,如果Y>0表明有余数, 打印出来 END
【运行示例】 输入:
Input A large number = 98765432100123456789 Input B number = 87654321
输出:
98765432100123456789 / 87654321 = 1126760563237 …… 6659712
【问题描述】
任意输入两个正整数A、B,求A/B的值,精确到第N位小数。
【问题分析】
当A、B都在计算机允许的显示精度范围内时,A/B的精确值有两种情况: (1)A能被B整除.A/B就是它们的精确值,没有余数。 (2)A不能被B整除,对余数要进行特殊处理. 首先观察一个具体的例子。
3/17=0.1764705
0.1764705 ---------- 17 ) 30 17 ---------- 130 119 ---------- 1lO
102 ---------- 80 68 ---------- 120 119 ---------- 100 85 ---------- 150
通过观察,我们可以看出,在作除法运算时,有一个不变的量和三个变化的量.一个不变量是除数.三个变化着的量中一个是被除数,一个是商,一个是余数.在做除法时,每次都是用被除数减去商与除数的乘积,若所得的余数不为零,则将其扩大10倍后再次作为被除数。继续试除,直到余数等于零或达到所要求的精度为止。
为了寻找被除数,除数.商和余数四者之间的关系,我们把上述除法的每一步骤列成表格如下: N 被除数A(N) 除数B 商D(N) 余数X(N) 0 3 17 0 3 1 30 17 1 13 2 130 17 7 11 3 110 17 6 8 4 80 17 4 12 5 120 17 7 1 6 10 17 0 10 7 100 17 5 15 . . . . . . . . . . . . . . .
从上表中,我们可以清楚地看出: A(N) = 10 * X(N-1) D(N) = INT(A(N)/B) X(N) = A(N)一D(N) * B
有了准确的计算公式,我们就可以设计一个程序,让计算机模拟除法的手算过程了。
程序清单及运行结果: REM 4_6.BAS
INPUT ―A,B,E=‖;A,B,E ‘ A表示被除数,B表示除数,E表示小数的位数 PRlNT A;―/‖,B,―=‖;
DIM A(E),D(E),X(E) ‘ 以小数位数设定数组的最大元素 A(0)=A:D(O)=INT(A/B) ‘ 计算出商的整数部分
X(0)=A(0)-D(O)*B :PRINT D(0);―.‖;‘计算出商的整数部分后,算出余数存入X(0) FOR I = 1 TO E
IF X(I—1)=0 THEN END ‘如果上一次余数为0,表示已除尽,则除法运算结束 A(I)= X(I-1)*10 ‘将上一次余数扩大10倍,结果存入A()
D(I)=INT(A(I)/B):PRINT USING―#‖;D(I);‘除法运算,商存入D() X(I)=A(I)-D(I)* B ‘余数存入X() NEXT I END
【运行示例】 输入:
A,B,E = 1,3,10 输出:
1 / 3 = 0.3333333333
对循环小数的处理
在除法运算中,如果不能整除,余数一般有三种情况; A 有限小数。 B 无限不循环小数, C 循环小数。
因此,对除法运算要有精度要求,即要指定运算结果中小数点后的位数。如果在这个范围内出现循环小数,则只要求计算出一个循环节即可。这就要求程序能判断是否出现了循环,并找到出现循环节的位置. 判断循环小数.主要看余数是否出现重复,若余数重复出现.则后面的得数一定与前面的相同,反复出现。
例如l/3,在求得一位商3之后,余数为l,与起始状态相同,所以商3循环出现。 又如求1/7的商,得到0.142857之后,余数又为1后面的商就以l42857循环出现。
再如1/24,得到商0.041之后,余数为16,补0再除,商数为6,余数仍为16,这个6就是一个循环节。 根据这个启发。我们把每次作除法运算后的余数记下来。相互进行比较,若发现一个余数在前面曾经出现过。则说明出现循环.这时只要把循环部分填在后面即可。
【问题描述】 求A/B的精确值
【问题分析】
在做除法运算时,用数组x记录每次相除后的余数.它的下标上界为计算精度的要求。在这个范围内,每求一次余数,都要与前边的余数进行比较,如果找到相同的余数,记下它的位置,做循环处理。若已超过精度要求还未出现循环,则不进行循环处理。
程序段如下: DO
A = A(I) * 10: I = I + 1 ‘上次余数扩大10倍 D(I) = A \\ B ‘除法运算
A(I) = A MOD B ‘取余数放入A() M = I + 1
IF A(I) = 0 THEN EXIT DO ‘如果本次余数为0结束除法 FOR J = 0 TO I - 1
IF A(I) = A(J) THEN M = J + 1: EXIT DO ‘如果本次余数与前边某一次余 数相同,记下位置做循环处理 NEXT J
LOOP UNTIL I = E
为了给循环小数加上循环节标志‗‘,在输出方法上需要稍加改动.不是计算一位输出一位.面是在求出最后结果后再一起输出。先输出商的整数部分,再标上小数点,然后输出数组D所记录的值。 程序段如下:
FOR K = 1 TO I ‘输出结果
IF M = K THEN PRINT \"'\"; ‘如果当前位是循环节起始位,打印循环节起始标记 PRINT USING \"#\"; D(K); ‘依次输出商各数位上的数 NEXT K
IF M < K THEN PRINT \"'\" ELSE PRINT ‘打印循环节结束标记
【程序清单】
REM 4_7.BAS
INPUT \" INPUT A,B,E :\"; A, B, E DIM A(E), D(E) PRINT A; \"/\"; B; \"=\";
I = 0: D = A \\ B: A(I) = A MOD B PRINT STR$(D); \".\"; DO
A = A(I) * 10: I = I + 1 D(I) = A \\ B A(I) = A MOD B M = I + 1
IF A(I) = 0 THEN EXIT DO FOR J = 0 TO I - 1
IF A(I) = A(J) THEN M = J + 1: EXIT DO NEXT J
LOOP UNTIL I = E FOR K = 1 TO I
IF M = K THEN PRINT \"'\"; PRINT USING \"#\"; D(K); NEXT K
IF M < K THEN PRINT \"'\" ELSE PRINT END
【运行示例】 输入:
INPUT A,B,E: 1,7,20 输出:
1 / 7 = 0. '142857'
【做一做】
计算77/119的商,如果是循环小数,打印输出时― ‘ ‖表示循环节。
【教法指导】
高精度除法是高精度运算的重点,也是难点。本节从最简单的除法运算入手,通过数学算式、图表等演示由浅入深地讲解高精度除法运算过程中被除数,除数.商和余数四者之间的关系,适时揭示出基本的程序段。在此基础上进行一定的扩展,使学生掌握A和商是高精度的除法,商是循环小数的除法等基本算法。
六、综合应用
印度国王的棋盘(JSOI2001小学组第3题)
[问题描述]:这是一个有名的古代故事。有一个数学家发明了一种棋盘献给了印度国王,数学家看国王非常欢喜,就向国王提出了奖赏的要求:在棋盘的第一格放一粒米,第二格放二粒米,第三格放四粒米,第四格放八粒米,.....也就是说每一格都放进了比前一格多一倍的米。国王认为这简直不值一提,就毫不犹豫的答应了。谁知结果却让国王大吃一惊, 当放到第64格时,就已经一共用了18446744073709551615粒米。这在当时要几百年才能种出来。现假定该棋盘共有200格,请你编程计算从第N格至第M 格共有多少粒米,并以三位一撇的形式输出。
[输入]: 键盘输入整数N,M(1≤N,M≤200不用判错)。
[输出]: 精确输出从第N格至第M 格共有多少粒米,并以三位一撇的形式输出。
[样例]:输入:N,M=20,37
输出:137,438,429,184
【问题分析】
该题要解决以下五个问题:
设有一个有200格很大的棋盘第1格放1(20)粒米,第2格放2(21)粒米,第3格放4(22)粒米,第4格放8(23)粒米……第n格放2n-1粒米。这是个计算2的高次乘方的问题,因乘积较大,超出QB的整数的取值范围,要用用高精度乘法来处理键盘输入n、m将第n格存放的米数至第m格存放的米数累加起来,同样其和超出QB的整数的取值范围,要用用高精度加法来处理输出这累加的米数
解法一:用高精度乘法、高精度加法
【变量说明】
a(201)数组用来存放n~m格米的和 b(200)数组用来存放某格的米数 n、m为键盘输入的第n格和第m格 c用来存放高精度进位的数 x用来存放高精度计算的临时乘积 y用来存放高精度进位的临时和 i、j循环变量 h定数组的用的变量 【算法分析】
1、输入n与m。定义数组a(201)、b(200),程序中用h=200来处理,因要进位,所以a()数组定义时比b()数组大1
2、用高精度乘法计算n格前(即n-1格)应放的米数,存放在b()数组中,用一个两重循环来处理, 外循环的循环变量1~n-2,特别要注意第n-1格应放的米数是2n-2,所以外循环的循环变量i的终值是n-2,外循环体中做两件事:
⑴用来进位的数初始化c=0
⑵内循环的循环变量1~h,在内循环体中做三件事: 对b()中的每一元素×2+c,临时存放在x中,即 x = 2 * b(j) + c
取出进位的数c供下次进位用,即 c = x \\ 10
对x取余,存入b()每一元素中,这是b()每一元素应得到的一位数,即 b(j) = x MOD 10
3、用一个两重循环来处理n~m格米数的和。外循环的循环变量n-1~m-1,外循环体中做两件事: ⑴用来进位的数初始化c=0
⑵内循环的循环变量1~h,在内循环体中所做的事分两部分,前三句: x = 2 * b(j) + c c = x \\ 10 b(j) = x MOD 10
这是b()数组每一个元素乘于2,第一次外循环b()×2,则b()中存放的是n格的米数(因在前b()存放的是n-1格的米数),以后每一次外循环,b()×2,则b()中存放的是n格以后格的米数,最后一次外循环b()中存放的是m格的米数;
后三句,是把b()每一元素的值累加到a()相应的每一元素中,
y = a(j) + b(j)语句是把b()每一元素的值加到a()相应的每一元素中,临时存放在y中 a(j) = y MOD 10语句是a(j)应得的一位数 a(j + 1) = a(j + 1) + y \\ 10语句加法进位
每次外循环,都把b()每一元素的值累加到a()相应的每一元素中,所以当外循环结束,a()中存放的是n~m格的总米数
4、按三位一撇的形式输出a()数组,分四步
⑴因a()数组开辟了200个单元,实际运算用不到这么大,a()数组中高位部分有不少单元存得是0,所以不输出a()数组中最高位部分的0,用下语句达到此目底: DO WHILE a(h) = 0: h = h - 1: LOOP 然后每三位加一逗号
⑵先测试h是否是3的整数倍
n = h MOD 3
如n为0则h是3的整数倍,如不为0则h不是3的整数倍 ⑶如n不为0则h不是3的整数倍,先输出前n位,加逗号: IF n > 0 THEN
FOR i = h TO h + 1 - n STEP -1: PRINT USING \"#\"; a(i); : NEXT: PRINT \END IF
⑷然后,每三位加一逗号输出,用j来控制每三位加一逗号 j = 0
FOR i = h - n TO 1 STEP –1 j = j + 1
PRINT USING \"#\"; a(i);
IF j MOD 3 = 0 AND i <> 1 THEN PRINT \NEXT i: PRINT 【程序清单】 h = 200
INPUT \"Input N,M =\"; n, m DIM a(h + 1), b(h)
b(1) = 1 ‘计算n-1格应放的米数,存放在b()数组中 FOR i = 1 TO n - 2 c = 0
FOR j = 1 TO h x = 2 * b(j) + c
c = x \\ 10: x = x MOD 10 b(j) = x NEXT j NEXT i
FOR i = n - 1 TO m - 1 ‘计算n~m格的米数,累加到a()数组中 c = 0
FOR j = 1 TO h ‘计算n+j-2格应放的米数,存放在b()数组中 x = 2 * b(j) + c c = x \\ 10 b(j) = x MOD 10
y = a(j) + b(j) ‘把b()每一元素的值加到a()相应的每一元素中 a(j) = y MOD 10 a(j + 1) = a(j + 1) + y \\ 10 NEXT j NEXT i
DO WHILE a(h) = 0: h = h - 1: LOOP ‘不输出a()数组中最高位部分的0 n = h MOD 3 ‘输出a()数组
IF n > 0 THEN ‘如数字的位数不是3的倍数,先输出前几位
FOR i = h TO h + 1 - n STEP -1: PRINT USING \"#\"; a(i); : NEXT: PRINT \END IF j = 0
FOR i = h - n TO 1 STEP –1 ‗以后,每三位加一逗号
j = j + 1
PRINT USING \"#\"; a(i);
IF j MOD 3 = 0 AND i <> 1 THEN PRINT \NEXT i: PRINT END
解法二:用高精度乘法、高精度减法 【变量说明】
a(200)数组用来存放1~m格的米数和 b(200)数组用来存放1~n-1格的米数和
两数组的差也存在a()数组中,则a()中存的是n~m格米的和 n、m为键盘输入的第n格和第m格 c用来存放高精度进位的数 x用来存放高精度计算的临时乘积 i、j、k循环变量 h定数组的用的变量 【算法分析】
由数学公式可知:20+21+22+23+……+2n-1=2n-1
所以计算20+21+22+23+……+2n-1就可以简化为计算2n-1 计算2n-1,就可以先计算2n,再在最低位减1即可 输入N与M。定义数组
用高精度乘法计算n格前(即n-1格)应放的米数,存放在b()数组中 这个程序段与前同,只是在最后多了一个 b(1) = b(1) – 1 这样用计算2n-1-1取代计算20+21+22+23+……+2n-2 用高精度乘法计算m格应放的米数,存放在a()数组中 同样多了一个 a(1) = a(1) – 1
这样用计算2m-1取代计算20+21+22+23+……+2m
用高精度减法,从a()数组中减去b()数组,其差仍存入a()数组,此时在a()中存放n~m格的米数,这个高精度减法程序段是一个计数循环: FOR k = 1 TO h
x = a(k) - b(k) 两数之差临时存入x
f = x < 0 f是个逻辑量,x为负数f=-1,否则f=0 a(k) = x - 10 * f 如x为负数,自动补10存入a(k) a(k + 1) = a(k + 1) + f 如f为-1,就自动从a(k+1)借1 NEXT k
按三位一撇的形式输出a()数组,集体算法同前 【程序清单】
INPUT \"Input N,M =\"; n, m DIM a(200), b(200)
b(1) = 1 ‘用高精度乘法计算2n-1,存放在b()数组中 FOR i = 1 TO n – 1 c = 0
FOR j = 1 TO 200 x = 2 * b(j) + c
c = x \\ 10 b(j) = x MOD 10 NEXT NEXT i
b(1) = b(1) – 1 ‘最低位减1,使b()数组中存放2n-1-1 a(1) = 1 ‘用高精度乘法计算2m,存放在a()数组中 FOR i = 1 TO m c = 0
FOR j = 1 TO 200 x = 2 * a(j) + c c = x \\ 10 a(j) = x MOD 10 NEXT NEXT i
a(1) = a(1) – 1 ‘最低位减1,使a()数组中存放2m-1
FOR k = 1 TO h ‘用高精度减法,从a()数组中减去b()数组中的值 x = a(k) - b(k): f = x < 0 a(k) = x - 10 * f a(k + 1) = a(k + 1) + f NEXT k
DO WHILE a(h) = 0: h = h - 1: LOOP ‘不输出a()数组中最高位部分的0 n = h MOD 3 ‘输出a()数组
IF n > 0 THEN ‘如数字的位数不是3的倍数,先输出前几位 FOR i = h TO h + 1 - n STEP -1: PRINT USING \"#\"; a(i); : NEXT: PRINT \END IF j = 0
FOR i = h - n TO 1 STEP –1 ‘以后,每三位加一逗号 j = j + 1
PRINT USING \"#\"; a(i);
IF j MOD 3 = 0 AND i <> 1 THEN PRINT \NEXT i: PRINT END
测试数据:
序号 输 入 输 出 1 N,M=14,18 253,952 2 N,M=4,16 65,528
3 N,M=26,44 17,592,152,489,984
4 N,M=16,123 10,633,823,966,279,326,983,230,456,482,242,723,840 5 N,M=150,200 1,606,938,044,258,989,561,918,115,739,361,222,073,379,218,269,035,224,643,928,064
本讲作业
1、请准确求出fibonacii数列的第N项与前N项之和。
2、高精度减法(JSOI2000小学组第3题)
键盘输入两个高精度的整数,编程实现这两个高精度整数的减法运算,两数均不会超过240位。要求输出该减法运算的算式与结果。 例如: 输入 输出
99998,9079 99998-9079=90919
123456,345678 123456-345678=-222222
3、、―鼠算遗题‖。这是日本数学家吉田光(1598-1672年)在1627年提出来的。他是这样说的:―正月里,鼠父鼠母生了12只小鼠,于是大小鼠共有14只。二月里,两代鼠全部配对,每对鼠又各生了12只小鼠。因此共有鼠98只。如这样下去,每月所有的鼠全部配对,每对鼠又各生了12只小鼠。十二个月后,鼠的总数是多少呢?‖假设每月都按这样的规律生,而所生的鼠又全部成活,一个都不夭折,十二个月后,鼠的总数是27682574402只。请编程,用高精度算法计算出这个值来。
4、 若一个数(首位不为零)从左向右读与从右向左读都是一样,我们就将其称之为回文数。 例如:给定一个十进制数56,将56加65(即把56从右向左读),得到121是一个回文数。 又如:对于十进制数87:
STEP1:87+78 = 165 STEP2:165+561 = 726 STEP3:726+627 = 1353 STEP4:1353+3531 = 4884
在这里的一步是指进行了一次十进制的加法,上例最少用了4步得到回文数4884。 写一个程序,给定一个十进制数M,将得到回文数的步骤逐步打印出来。 如果20位数范围内不可能得到回文数,则输出―error‖
因篇幅问题不能全部显示,请点此查看更多更全内容