不限制位数的整数高精度乘法★★★★
这是“高精度算法”系列文章中的第二篇。在“高精度加、减、乘、除”这4种计算中,加法最基础、最简单,乘法稍难,减法更难,除法最难。
我们就接着来研究正整数多位数高精度乘法的计算方式吧。
下面这段话是“原创”性的,它不仅指出LOGO系统自身的一个错误,还与我们只能使用“数组”编程来进行所有的高精度计算有关。
在各种计算机程序设计语言中,“数值”和“字符串”都有严格而明显的界限。但是在LOGO语言中,可能是为了使概念简单化,把“数值”和“字符串”混为一谈,造成编写程序的时候可能出现意想不到的错误。
这里我们要先来讨论一下LOGO系统软件中一个错误。到目前为止还没有见到那个人胆大到声言“LOGO系统本身就有错误!”但是根据林老师的见解:LOGO系统内部在处理“字符串”和“数值”时确实显得有些“傻”。请你在文本区输入以下命令:
? BF "A98765
Result: 98765
? BF "A987654321000
Result: 9.88E+11
BF命令的功能是“输出指定的字或表中,除了第一个字符或元素之外的其他字符或元素”。上面两个例子中,输入的数据显然都是“字符串”。
第一次处理字符串"A98765时输出是正确的。第二次处理字符串"A987654321000时明显出现了错误:LOGO系统把后面剪切下来的字符串又作为数值处理了(输出的是科学记数法的数值)。遗憾是LOGO系统内的这个错误我们根本无法纠正!只能绕道采用特殊的编写程序的方式预防错误的发生。
所以,即使是在显示算式时,我们别无选择,只能从数组中还原输入的数字,而无法用较为简单的BF命令直接“剪取”输入的字符串中的数字。
LOGO系统的“璧玉微瑕”并不妨碍我们发挥它的强大计算功能。
任意位数高精度乘法计算的思路是这样的:
在输入的数字前面加一个字母,使数字作为字符串输入,这样就能处理长数字。
剪切掉开头的字母,把后面的数字先作为字符读出,再用求ASCII值的方式还原成一个个数字并存入数组。
我们估算乘积的位数最多为“被乘数的”数位加上“乘数”的数位。
然后用:I、:J两重循环实现乘法,实际上是模仿手工逐位乘法。
每位乘出来的积马上存储在数组:JC中。
每乘一个数位后,马上处理数组:JC中的进位。这是这个程序中比较抽象的部分。
最后显示输出结果。这才是这个程序的核心部分:我们先设置“标志位”变量:FLAG的值为0,当遇到数组:JC前面的“空位(连续数值为0)”时,越过。当出现第一个不为零的数位时,意味着从这里开始都是有效数位,全部照样输出,直至输出结束。输出有效数位的部分使用了GO—LABEL命令。我们已经一再强调,使用这个命令要小心慎重。但是在这里,GO—LABEL命令起到了其他命令难以替代的作用。
程序的强大功能是不容置疑的。请看计算输出实例。
TO CHENG_N ;任意位数乘法
PR
"请输入一个乘数并在数字前加上1个任意字母:
MAKE "A
READ ;从键盘上读入被乘数
MAKE "A1 COUNT
:A ;测试数的长度
PR
"请输入另一个乘数并在数字前加上1个任意字母:
MAKE "B
READ ;从键盘上读入乘数
MAKE "B1 COUNT
:B ;测试数的长度
MAKE "C
:A1+:B1 ;计算乘积空间长度
MAKE "JA
BYTEARRAY
:A1 ;建立被乘数数存储空间
MAKE "JB
BYTEARRAY
:B1 ;建立乘数的存储空间
MAKE "JC
BYTEARRAY
:C ;建立储存积的存储空间
FOR "I 1
(:A1-1)[ASET :JA :I (ASCII(ITEM :A1-:I+1 :A))-48]
;将被乘数拆位存储
FOR "I 1
(:B1-1)[ASET :JB :I (ASCII(ITEM :B1-:I+1 :B))-48]
;将乘数拆位存储
;%%%%%%%%以下程序段执行逐位乘法计算%%%%%%%%%%
FOR "I 1
(:B1-1)[\
FOR "J 1 (:A1-1)[\
ASET :JC :I+:J-1 (AGET :JC :I+:J-1)+(AGET :JA :J)*(AGET :JB :I)
JW]]
;===============显示输出算式=================
FOR "I 1
(:A1-1)[TYPE AGET :JA :A1-:I] ;显示被乘数
TYPE[*]
FOR "I 1
(:B1-1)[TYPE AGET :JB :B1-:I] ;显示乘数
TYPE[=]
MAKE "FLAG
0
MAKE "N
:C-1 ;共显示:N是数位
LABEL
"LOOP ;输出有效数字程序段
IF :N=0 [PR[]STOP] ;输出数位到此结束
MAKE "S AGET :JC :N ;获得当前位的数值
IF (AND :FLAG=0 :S=0) THEN[MAKE "N :N-1 GO "LOOP]\
ELSE[MAKE "FLAG 1]
IF :FLAG=1 THEN TYPE :S ;对有效位输出显示
MAKE "N
:N-1 ;指向后一个数位
GO
"LOOP ;继续显示其余数位
END
TO JW ;计算乘法进位子程序
FOR "K 1
(:C-1)[IF 9
ASET :JC :K+1 (AGET :JC :K+1)+INT((AGET :JC :K)/10) \
ASET :JC :K (REMAINDER (AGET :JC :K) 10)]]
END
? CHENG_N
请输入一个乘数并在数字前加上1个任意字母:
? A9876543210000087654
请输入另一个乘数并在数字前加上1个任意字母:
?
A678234587654300010099
9876543210000087654*678234587654300010099=6698613211484286042020756127803085217746
? CHENG_N
请输入一个乘数并在数字前加上1个任意字母:
? A100000000
请输入另一个乘数并在数字前加上1个任意字母:
? A100000000000
100000000*100000000000=10000000000000000000
? CHENG_N
请输入一个乘数并在数字前加上1个任意字母:
? A99999999912345
请输入另一个乘数并在数字前加上1个任意字母:
? A1266789008
99999999912345*1266789008=126678900688959609503760
计算的结果表明:再多的数位也能正确计算!
这里是新颖有趣的LOGO、DEV-C++语言之家
欢迎评论 欢迎转载
查找林老师博客最便捷的方法:
在百度、谷歌、搜狗、搜搜、雅虎、有道等搜索引擎中输入
林老师 LOGO
就能找到林老师博客文章了
查阅林老师最新发表文章的链接:
快速检索数百篇博客提高阅读效率的链接:
因网络拥挤“纸条”常不能及时打开查阅。有信息尽量使用“评论”或邮件。
需要LOGO系统文件常用表格工具文件及DEV-C++系统文件的可以发邮件给林老师
声明:
林正山老师发表的文章及照片,媒体、网站或出版物未经本人许可谢绝进行任何形式的删节、改编、重组及转载。
允许个人博客按原文(含图片及附注)进行完整转载,转载时敬请注明本博作者姓名、文章原始出处,并以链接形式标明来源。