用户:
KIHIO查看:0 回复:0 评论:0 创建时间:2021-10-05T14:59:52
我做了一个2~16进制的转化运算程序(不支持小数和负数),如果你没看到,请进入这个链接:
https://shequ.codemao.cn/community/405210
但是这里没有详细介绍原理,我这就来给大家简单易懂地介绍一下(注意了,这里多次提到“循环轮数”这个词,实际上第一次循环的循环轮数为0,第二次为1,第三次为2,以此类推,可不要搞错了):
首先,我们需要把进制转化的代码包装成一个函数,这样的话,如果出现特殊情况,必须结束程序时让函数返回0就行了,实现代码如下:
def main():
#进制转化的代码
#如果把进制转化的代码包装在函数内,那么当需要停止程序时,使函数返回0就行了。
而这里有一行代码:
#进制转化的代码
我们现在介绍的都和里面的代码有关,但我们要输入被转化数字的进制数并判断输入是否为数字,代码如下:
try:
j1=float(input('请输入被转化数字的进制数:')) #被转化数字的进制数在教学中存储在j1变量里。
except ValueError: #判断输入是否真的是数字。
print('输入错误,程序已停止运行。')
return 0 #强制退出 main() 函数,使程序停止运行。
也许有人会提出疑问:第二行代码中输入的j1的输入为什么要转化为浮点型而不是整型呢?那是因为,我们以后要判断j1是否为小数,转化为整型就不能判断了。
同样,输入已转化数字的进制数的原理也是一样,只不过在教学中存储的变量由j1变为了j2:
try:
j2=float(input('请输入已转化数字的进制数:')) #已转化数字的进制数在教学中存储在j2变量里。
except ValueError: #判断输入的数是否真的是数字。
print('输入错误,程序已停止运行。')
return 0 #强制退出 main() 函数。
接下来,我们要判断j1和j2的输入是否是不合格的数字,我们要分成两个部分来判断:
一、判断j1和j2是否为小数
二、判断j1和j2的值是否超出程序可计算的进制范围
但是,想实现第一个部分的判断比较困难,而困难点在于用PYTHON代码判断一个数是否为小数的代码,这里我给你一个简短的标准判断代码(代码中被判断数值为x变量):
int(x)!=x #如果这串代码返回成立,那么x为小数;如果这串代码返回不成立,那么x为整数。
有了这样的代码,我们就可以达成第一个部分的判断:
if int(j1)!=j1 or int(j2)!=j2: #判断j1和j2是否为小数。
print('输入错误,程序已停止运行。')
return 0 #强制退出 main() 函数,终止程序运行。
但这时,j1和j2还是浮点型,我们要把它们转化为整型:
j1=int(j1) #将j1和j2转化为整型。
j2=int(j2)
不过,现在我们还要完成第二部分的判断,这就容易了,代码如下:
if (j1>16 or j2<2) or (j1<2 or j2>16): #判断j1和j2的值是否在程序能转化的进制范围内。
print('输入错误,程序已停止运行。')
return 0 #强制退出 main() 函数。
现在我们还要输入被转化数字,代码如下:
n=input('请输入被转化数字:') #被转化数字在教学中存储在n变量里。
注意啦,我们不要盲目把n变量的输入转化为整型,不然当用户输入a或b或c或d或e或f时,程序就会报错。
接下来,我们要读取n变量中每个字符对应的数字(0对应0,1对应1,2对应2,3对应3,4对应4,5对应5,6对应6,7对应7,8对应8,9对应9,a对应10,b对应11,c对应12,d对应13,e对应14,f对应15)方便我们用乘权相加法转化成10进制,毕竟作品的大致原理就是把被转化数字转化为10进制,再把10进制数转化为已转化数字的进制数。
我们在转化前要定义一些变量,用途我在注释上已经写好了:
i=0 #计算读取n变量中每个字符对应的数字用的循环的轮数。
aa=['a','b','c','d','e','f'] #aa列表中有16进制中a、b、c、d、e、f中六个数字,而aa[n]对应的数字就是bb[n]。
bb=[10,11,12,13,14,15]
ts=[] #ts列表用来存储读取n变量中每个字符对应的数字的结果。
注:在这以后,我会把读取n变量中每个字符对应的数字简称为读取。
先不谈论注意事项,现在就开始读取吧!首先,我们要用i变量计量轮数,代码如下:
for i in range(0,len(n)):
#其它读取用的代码
不过,这两行代码中有一行代码:
#其它读取用的代码
我们将重点谈论这里面的代码。
但是,我们刚进入“#其它读取用的代码”里面的代码的世界的时候,我们还要定义一个变量(定义的变量名为s):
s=0 #用于存储n变量的第i+1位对应的数字是否大于等于10,存储的数值为1代表是,存储的数值为0代表不是。
不过,我们怎么判断n的第i+1位对应的数字是否大于等于10呢?答案是:看n的第i+1位是否为数字,是就代表n的第i+1位对应的数字小于10,不是就代表n的第i+1为对应的数字大于等于10。
所以,这个判断n的第i+1位对应的数字是否大于等于10的代码就诞生了:
try:
cs=int(n[i])
except ValueError: #判断n[i]是否为数字。
s=1 #当n[i]为非数字时,设置s为1。
但是,我们还要把数据添加到ts列表里,这时候,就需要这样的代码了:
if s==0: #判断n[i]对应的数字是否大于等于10。
ts.append(int(n[i])) #在n[i]对应的数字小于10的情况下,n[i]对应的数字等于int(n[i])
else:
#在n[i]对应的数字大于等于10的情况下,用列表aa和bb读取n[i]对应的数字的代码。
现在,我们这里有这行代码:
#在n[i]对应的数字大于等于10的情况下,用列表aa和bb读取n[i]对应的数字的代码
这里面的代码需要我们的探讨。
但是,我们又需要定义两个变量:
j=0 #当n[i]对应的数字大于等于10时,用于计算判断n[i]对应的数字到底是几用的循环的轮数。
fl=0 #当n[i]不是数字时,用于存储代码是否能判断n[i]对应的数字,存储的数值为0表示不能判断,存储的值为1表示能判断。
这时候,我们就要写判断n[i]对应的数字到底是几用的循环的代码了:
for j in range(0,6): #j从0到5循环,如果aa[j]==n[i],那么n[i]对应的数就是bb[j]。
if aa[j]==n[i]: #判断aa[j]是否和n[i]相等。
fl=1 #相等代表代码能算出来n[i]对应的数,这时要把fl设为1。
break
现在,我们把n[i]对应的数字存储到列表ts(用于存储n的每一位对应的数):
if fl==1: #用代码能否判断n[i]到底对应几,不能判断那么n[i]肯定有问题。
ts.append(bb[j])
else:
print('输入错误,程序已停止运行。')
return 0 #强制退出 main() 函数。
这样,在n[i]大于等于10的情况下读取n[i]对应的数字的工作就完成了。
但是,我们还要判断n[i]对应的数字是否超过被转化数字的进制数的范围,判断代码如下:
if ts[i]>=j1: #n[i]与ts[i]相同,所以只要判断ts[i]是否大于等于j1,就能判断n[i]对应的数是否超出被转化数字的进制数的范围了。
print('输入错误,程序已停止运行。')
return 0 #强制退出 main() 函数,以使程序停止运行。
这样,我们就成功读取了n变量中每个字符对应的数字。
但是,我们还要把ts列表转化为10进制数字(看到这不必惊讶,这个东西的原理就是把被转化数字转化为10进制,再把10进制数转化为已转化数字的进制数),代码如下:
s1=0 #用s1变量存储转化好的10进制数字。
for i in range(0,len(ts)): #我们用i变量来计算循环轮数。
s1+=ts[i]*(j1**(len(ts)-1-i)) #我们这里用乘权相加法,公式就是s1+=ts[i]*(j1**(len(ts)-1-i)),但为什么j1要**(len(ts)-1-i)而不是i呢?由于i越大位数反而越低,而在乘权相加法中,位数越低的幕越低,所以用j1直接去**i是不行的,应该用j1去**(len(ts)-1-i)。
接下来,我们就用短除法把s1转化为已转化数字的进制数,这就需要定义一个列表,功能在注释上有说过,代码如下:
#列表s2yd用于存储从低位到高位的转化好的用已转化数字的进制数写的数字。
if s1==0: #如果s1=0,那么系统就不会自动计算列表s2yd的值,此时把s2yd赋值为空列表就会导致BUG,所以应该赋值为[0]。
s2yd=[0]
else:
s2yd=[]
现在我们得用短除法来进行计算,代码如下:
while s1>0: #在短除法中,商为0时即可罢休,而s1被赋值为商,所以s1为0后方可罢休。
s2yd.append(s1%j2) #因为用的是短除法,所以可以用s2yd.append(s1%j2),毕竟本来就要存储s1%j2,但这会导致列表s2yd是从低位到高位排列的。
s1=int(s1/j2) #计算这一步的商要用 int(s1/j2) 而不是 (s1/j2) 不然商会出现小数,导致BUG。
但是这样会导致s2yd中存储的数是从低位到高位存储的,我们现在要转化为从高位到低位存储的值,但要给一个变量赋值,并定义一个列表,代码如下:
i=len(s2yd)-1 #i用于计算将s2yd转为从高位到低位存储的值用的循环的轮数,但实际循环轮数是len(s2yd)-1-i。
s2y=[] #用于存储从高位到低位的已转化数字。
接下来,我们就要开始计算从高位到低位的已转化数字了,代码如下:
while i>=0: #我们这里用的是一个一个算,当i=0时就算好了,方可罢休。
s2y.append(s2yd[i]) #因为s2yd是从低位到高位排序,所以i越大,用s2yd[i]读取出来的位数就越大,因此可以先把i赋值为len(s2yd)-1,再按顺序依次减少,用s2y进行append,这样就转化好了。
i-=1
但是,这样的话s2y每一位a会变成10,b会变成11,c会变成12,d会变成13,e会变成14,f会变成15(其实s2yd也有这个问题)所以我们要把已转化数字存储到变量内,并将10转化成a,11转化成b,12转化成c,13转化成d,14转化成e,15转化成f。这时候的代码如下:
s2=' ' #这是存储已转化数字用的变量。
for i in range(0,len(s2y)): #i代表这个循环的轮数,而这个循环正是计算s2的数值用的
#计算s2的值用的其它代码
那么,计算s2的值用的其它代码到底是什么呢?揭晓答案:
if s2y[i]<10: #s2y[i]小于10时没有问题,可以直接储存进来。
if s2==' ': #当s2==' '时,s2不能去喵然会出BUG,但如果s2!=' ',那么就必须让s2去加str(s2y[i])了。
s2=str(s2y[i])
else:
s2=s2+str(s2y[i])
else: #s2y[i]大于等于10时就有问题了,需要把10转化为a、11转化为b、12转化为c、13转化为d、14转化为e、15转化为f。
if s2==' ': #在s2y[i]>=10的转化关系上,我们说把10转化为a,实际上aa[0]也等于a,说把11转化为b,实际上aa[1]也等于b,说把12转化为c,实际上aa[2]也等于c,说把13转化为d,实际上aa[3]也等于d,说把14转化为e,实际上aa[4]也等于e,说把15转化为f,实际上aa[5]也等于f,你看,一个数要转化的字母就是aa[这个数-10],所以在s2y[i]大于等于10时,可以用aa[s2y[i]-10]转化成字母。
s2=aa[s2y[i]-10]
else: #s2y[i]>=10时跟<10时一样,也是当s2==' '时,s2不能去加aa[s2y[i]-10],不然会出BUG,但如果s2!=' ',那么就必须让s2去加aa[s2y[i]-10]了。
s2=s2+aa[s2y[i]-10]
这样,s2的数就求出来了,但我们还要打印s2,代码如下:
print('已转化数字:'+s2) #打印s2的值。
return 0 #不写最后一行代码return 0的话会导致在打印后出现BUG,因为函数的一个分支没有返回。
这样,函数就写好了,但是我们还要调用,代码如下:
x=main() #其实还可以写作 main()
这样,我们的2~16进制转化程序就大功告成了,赶快去调试一下吧!