第12课 小数字大学问
小数字大学问(进制)
加法中有进位,那是一种计数方法,我们把这种带有进位的计数方法称为“进制”。

脑洞大开
想一想我们身边都有哪些进制?
十进制是我们最常用的进制。看看我们的手指,十进制的发明跟我们人类有10个手指有关。小时候,我们也习惯用手指来帮助计数。
还有六十进制,时间的表示中广泛使用了六十进制,一小时=60分钟,一分钟=60秒,60秒进位1分钟,60分钟进位1小时。
还有二十四进制,24小时就是一天;十二进制,12个月就是一年;等等。开动脑筋想想还有什么进制?
提出思考
既然人类习惯使用十进制,那为什么发明的计算机要使用二进制呢?

提问是发明创造的开始。当初首先想到的应该是十进制,那用什么方式来表示不同的数字呢?
计算机是需要用电的,因此想到了电压,不通电时的电压0伏特表示数字0,通电后的电压1伏特表示1,2伏特表示2……10伏特表示10。看上去特别棒,但是电器件在使用过程可能会老化,同时外部环境也可能导致电压不是那么标准。当电压出现了2.5伏特时,到底表示的是2还是3呢?

再思考一下,拉开数字之间的电压差距之后会怎样呢?假设将10伏特算作1,以10伏特为中心电压差距正负10内也都算作1,也就是0~20伏特的电压范围都算作1,那么这样来表示数字9,估计电压快要到200伏特了。
那有没有更好的办法呢?当然有,二进制由此诞生,只需要通电和不通电就可以解决,有电压表示1,没电压表示0,从此不需要那么纠结了。


进制转换

运行程序,输入:
输出结果为:
八进制:21
十进制:17
十六进制:11
(1)printf("八进制:%o\n十进制:%d\n十六进制:%x",num,num,num):将输入的十进制数字按照八进制、十进制、十六进制分别输出。
(2)%o按八进制输出,%d按十进制输出,%x按十六进制输出。
(3)\是转义符,\n表示回车换行。因此一行的内容被分成了3行。
划重点
输入数字17,按照不同的进制输出了不同的结果。从我们最熟悉十进制开始,一起研究一下进制。
①熟悉的十进制:

11、12、13、14、15、16、17
②再看看八进制:

注意
这里的17,是八进制进位1,相当于8+7=15,而不是十进制的17。

这里的20,拆分成进位的2和数字0,也就是十进制的数字16=2×8。
继续计数。
八进制的21对应的是十进制的17。
③现在攻克十六进制:
十六进制可以一直数到15呢,但是需要用字母替代。
0、1、2、3、4、5、6、7、8、9、a(十进制的10)、b(十进制的11)、c(十进制的12)、d(十进制的13)、e(十进制的14)、f(十进制的15)。

加1得到的十六进制数值11就对应十进制的数值17啦!这里的11拆成1和1,第一个1代表十进制16。
敲黑板
①探寻进制的奥秘,拆解十进制数字2023。
在十进制里面只有数字0~9,当继续计数就需要进位,这时10就诞生了。



十进制的规则就是满十进一,进1位相当于×10,进2位就是×10×10,进3位就是×10×10×10。

现在一起来拆解2023吧。
2×10×10×10 + 0×10×10 + 2×10 + 3=2023
②探寻八进制的365。
八进制中的10,在十进制中就是1×8 + 0=8。
八进制中的100,在十进制中就是1×8×8 + 0×8 + 0=64。
现在来拆解八进制的365。


十进制转八进制
将十进制转换成其他进制有一种通用的方法:短除法。
来吧,试试将十进制数字275转换成八进制数。

(1)使用短除法不断地除以8,直到商为0。
(2)将余数倒序组合起来,即将4、2、3拼接起来。
(3)得到八进制结果423。
这就是使用短除法进行进制转换的过程。
提出思考
为什么短除法就可以将十进制转成其他进制呢?
十进制的275转换成八进制是423。
进制是逢几进一,这是进制的规则,因此八进制的423也遵循这个规则,逢八进一。
从423变成十进制,这个我们之前已经探索了。
4×8×8 + 2×8 + 3
下面对比一下进制转换的过程。

假设我们将八进制转换成十进制视为一种顺向思维,那么十进制转换回八进制就可以运用逆向思维来思考。
现在你知道为什么短除法可以将十进制转换成八进制了吗?
通过乘得到的答案,再通过除回去,就这么简单。
乘了几个8,反过来就需要除以几个8。
提出思考
怎么没有二进制呢?
printf()没有转换成二进制的格式。但是我们依然可以运用之前学习过的循环来实现。
(1)把二进制数101转换成十进制数:



将计算结果相加:4 + 2 +1=7。
(2)十进制118转换成二进制数:

直到商为0,将余数倒序连接起来,为1110110。

十进制转二进制

翻译助力理解
●pause:暂停。
(1)使用while(true){}不断进行短除法。
(2)短除法分为两步,第一步求余数binary=num % 2,第二步求商num=num / 2。
(3)cout<<binary<<"商为:"<<num表示每一步都将结果输出。
(4)system("pause")表示暂停程序,等待按键继续执行程序,便于我们观察和推进短除法。
运行程序,输入数字:
输出结果为:
1商为:10请按任意键继续. . .
0商为:5请按任意键继续. . .
1商为:2请按任意键继续. . .
0商为:1请按任意键继续. . .
1商为:0请按任意键继续. . .
观察结果,当商为0时,程序不用继续执行,将余数从下往上组合起来,即可得出十进制数21对应的二进制数10101。
敲黑板
研究程序最好的方式就是跟随程序步骤逐一分析。



巩固练习
(1)将十进制数42转换为二进制数,得到的结果是()。
A.001010
B.101010
C.010101
D.110101
(2)八进制数系统中包含的数字范围是0到7。()√()×
(3)请编写一个程序,接收用户输入的十进制整数,将它转换为八进制数和十六进制数,并输出结果。
探索思考
如果程序能在转换完成后自动停止那该多好,这就省去了观察商变化的时间。
阅读以下代码,思考一下为什么改成num>0后,程序就自动停止了呢?
划重点
while(){}的圆括号里面的true变成了num>0,条件发生了变化,之前的true表示条件一直成立,num>0表示只有num大于0条件才成立,那么当商为0时,条件不成立,循环也就不继续了。


拓展探索
之前说到printf()没有二进制的输出格式,现在阅读以下代码学习一下如何快速进行进制转换。

(1)cout<<"二进制表示:"<<bitset(num)<<endl:这行代码用于将num以二进制表示。它使用了bitset类,将整数num转换为一个包含二进制的字符串,并输出到标准输出流cout中。sizeof(int)*4用于指定二进制字符串的长度,将4分别改成2和8,运行程序观察字符串长度的变化。
(2)cout<<"八进制表示:"<<oct<<num<<endl:表示使用oct控制符将整数num以八进制格式输出。
(3)cout<<"十六进制表示:"<<hex<<num<<endl:表示使用hex控制符将整数num以十六进制格式输出。

