加法中有进位,那是一种计数方法,我们把这种带有进位的计数方法称为“进制”。
脑洞大开
想一想我们身边都有哪些进制?
十进制 是我们最常用的进制。看看我们的手指,十进制的发明跟我们人类有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,从此不需要那么纠结了。
进制转换
运行程序,输入:
17
输出结果为:
八进制: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
八进制的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)。
11
加1得到的十六进制数值11就对应十进制的数值17啦!这里的11拆成1和1,第一个1代表十进制16。
敲黑板
①探寻进制的奥秘,拆解十进制数字2023。
在十进制里面只有数字0~9,当继续计数就需要进位,这时10就诞生了。
10
100
1000
十进制的规则就是满十进一,进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") 表示暂停程序,等待按键继续执行程序,便于我们观察和推进短除法。
运行程序,输入数字:
21
输出结果为:
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<sizeof(int) * 4>(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以十六进制格式输出。