第一章 0 的故事–计数法
10 进制计数法
2 进制计数法
基数转换
计算机为什么用 2 进制
10 进制计数法
数字有 0、1、2、3、4、5、6、7、8、9 共 10 种
数位从右往左分别表示个位、十位、百位、千位
小学一年级的回忆:老师让写「十二」,我听成 12 就写下 10 和 2,本子上写的是 102,老师说该写 12 喔
2503 的分解:2 个 1000、5 个 100、0 个 10、3 个 1
#ruby
# 2503 = 2 x 10**3 + 5 x 10**2 + 0 x 10**1 + 3 x 10**0
puts 2 * 10**3 + 5 * 10**2 + 0 * 10**1 + 3 * 10**0 # 2503
# 1100 = 1 x 2**3 + 1 x 2**2 + 0 x 2**1 + 0 x 2**0
puts 1 * 2**3 + 1 * 2**2 + 0 * 2**1 + 0 * 2**0 # 1210 进制计数法的数位全是 10 的幂,这个 10 称作基数(底)
2 进制计数法
数字只有 0、1 共 2 种
数位从右往左分别表示 1 位、2 位、4 位、8 位
数数时到 2 就进位:0、1、10、11、100、101
同样地,1100 是 1 个 8、1 个 4、0 个 2、0 个 1
10 进制 2 进制 10 进制 2 进制 0 0 9 1001 1 1 10 1010 2 10 32 100000 3 11 64 1000000 8 1000 99 1100011
基数转换
10 进制转 2 进制:反复除以 2,看余数是 0 还是 1,再把余数逆向排列
#ruby
# 12 转 2 进制:反复除以 2,余数从下往上读
n = 12
while n > 0
puts "#{n} / 2 = #{n / 2} 余数 #{n % 2}"
n /= 2
end
# 12 / 2 = 6 余数 0
# 6 / 2 = 3 余数 0
# 3 / 2 = 1 余数 1
# 1 / 2 = 0 余数 1余数从下往上读就是 1100,2503 同理得到 100111000111
#ruby
def to_bin(n)
bits = []
while n > 0
bits << n % 2
n /= 2
end
bits.reverse.join
end
puts to_bin(12) # 1100
puts to_bin(2503) # 100111000111
puts 2503.to_s(2) # 100111000111
计算机为什么用 2 进制
计算机表示数只有两种状态:开关切断(0)和开关连通(1)
开关个数可以增加,够多就能表示多大的数
做成能表示 10 种状态的开关理论上也行,结构必定更复杂
1 位加法表的差别最直观
+ 0 1 0 0 1 1 1 10 10 进制的 1 位加法表是 10 x 10 = 100 格,2 进制只有 2 x 2 = 4 格
缺点是位数变多:2503 在 10 进制是 4 位,在 2 进制是 12 位
10 进制位数少、数字种类多,人类用着顺手,两只手正好 10 个指头
2 进制数字种类少、规则简单,计算机不会算错,也不用靠直觉比大小
所以计算机执行人类的任务时:10 进制 -> 2 进制 -> 计算 -> 10 进制
#ruby
# 21 + 19:转 2 进制 -> 用 2 进制算 -> 转回 10 进制
a = 21.to_s(2)
b = 19.to_s(2)
sum = (a.to_i(2) + b.to_i(2)).to_s(2)
puts "#{a} + #{b} = #{sum} -> #{sum.to_i(2)}"
# 10101 + 10011 = 101000 -> 40