像二进制和十六进制这样的进制系统乍看起来有点奇怪。关键在于理解不同的系统在“满”时如何像里程表一样“进位”。十进制系统(Base 10)在达到10个项目时“进位”,创建新的一位。我们等待60秒后才“进位”到新的一分钟。十六进制和二进制类似,但分别在每16个和每2个项目时“进位”。
尝试在这里将数字转换为十六进制和二进制:
很久以前:一元数
很久以前,我们还没有进制系统!那时无论上坡下坡,都要穿过积雪和酷热。当你想数一个时,你会写:
l
当你要数5时,你会写
lllll
显然,1 + 5 = 6
l + lllll = llllll
这是最简单的计数方式。
罗马人登场
在罗马数字中,二是一的两倍。三是一的三倍:
one = I
two = II
three = III
然而,他们决定可以做得比在沙子上画线的古老传统更好。对于五,我们可以用V来表示lllll,得到类似
l + V = Vl
不错吧?当然,你还可以使用更多符号(L、C、M等)。
关键点是,V和lllll是编码数字5的两种方式。
给每个数字起名字
另一个突破是认识到 每个数字 可以是一个独立的概念。与其将三表示为一串一,不如给它自己的符号:“3”。从一到九都这样做,你就得到了这些符号:
1 2 3 4 5 6 7 8 9
罗马数字已经很接近了,非常接近,但只给了5、10、50、100、1000等独特的符号。
利用位置
显然,你无法给 每一个 每个数字都赋予自己的符号,因为数量太多了。
但请注意罗马数字的一个洞见:它们使用 位置 符号的组合来表示意义。
IV 表示“从5中减去1”,
而 VI 表示“在5上加1”。
在我们的数字系统中,我们以类似的方式使用位置。我们 始终相加 只加不减,每个位置都是前一个位置的10倍。
所以,35 表示“加 3*10 到 5*1”,而 456 表示 4*100 + 5*10 + 6*1。这种“按位十进制”的设定就是我们今天使用的印度-阿拉伯数字系统。
我们选择十进制
为什么我们每次选择乘以10?很可能因为我们有10根手指。
有一点需要认识到:我们需要足够的数字来“填充”,直到达到下一个数字。让我演示一下。
如果我们想每10个数就滚动一次里程表,就需要1到9这些数字符号;我们还没到10。想象数字缓慢向上递增——在什么时候你会翻到下一个单位并从零开始?
引入零
当我们达到10时会发生什么?我们如何表示我们想要恰好一个“十”而“个位”列没有东西?
我们使用零,那个不存在的数字。零是一个相当了不起的概念,它是一个占位符,一个空白,一个空位,还有很多其他含义。可以说,零是有史以来最伟大的发明之一。
零使我们能够拥有一个空的占位符,这是罗马数字所没有的。看看没有零时他们的数字是多么笨拙。
乔治·奥威尔著名小说《1984》将写作“MCMLXXXIV”!读起来朗朗上口,不是吗? ![]()
考虑其他进制
记住我们 选择 每十次就滚动里程表一次。我们的计数如下:
1 2 3 4 5 6 7 8 9 (uh oh, I’m getting full!) 10 (ticked over – start a new digit)
如果我们像对待秒和分钟那样,每60次才进位一次呢?
1 second 2 3 4 5 … 58 59 1:00 (60 seconds aka 1 minute. We’ve started a new digit.)
到目前为止没问题,对吧?注意,我们使用冒号(:)表示进入了一个新的“位”。在十进制中,每个数字可以独立存在。
尝试十六进制
如果我们想要十六进制,可以类似地做:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 (we’re getting full) 1:00 (16 – we’ve started a new digit)
然而,我们不想用冒号记法来写十六进制数(尽管我们可以)。我们更愿意为10-15创造单独的符号,这样我们就可以像平常一样直接写数字了。我们已经用完数字(1-9已用,0作为占位符),所以需要其他符号。我们可以用一些波浪线或其他形状,但惯例是用字母,罗马风格。就像5变成V,程序员用字母A-F来凑足16个数字。也就是说:
1 2 3 4 5 6 7 8 9 A (10 – we’re using the symbol “A”) B (11) C (12) D (13) E (14) F (15 – uh oh, we’re getting full) 10 (16 – we start a new digit)
啊哈!现在每个“位”可以用一个数字表示,而且我们知道10实际上意味着“已进位到16”一次。
20意味着进位到16两次(32)。
25意味着进位到16两次(得到32)再加额外的5。总共是32+5=37。
快速回顾
跟得上吗?这很酷,对吧?我们可以在任意进制下计数。另外注意,十六进制更“节省空间”,比如数字11可以写成单个数字B。
十六进制与十进制其实没多大区别,只是更大才进位。
奇妙的二进制世界
我们已经见过很多进制,从最简单的的一元,到繁琐的罗马数字,稳定的十进制和紧凑的十六进制。
二进制好在哪里?本着简单的精神,它是具有“进位”概念的最简单的数字系统。一元,只是写1,11,111……无穷无尽。二进制有两种选择(1和0),如下:
1: 1 2: 10 (we’re full – tick over) 3: 11 4: 100 (we’re full again – tick over) 5: 101 6: 110 7: 111 8: 1000 (tick over again) …
等等。
因为二进制非常简单,所以很容易用硬件实现。你只需要能开关的东西(表示1和0),而不是需要10种状态的东西(表示十进制)。
因为它非常简单,二进制还能抗干扰。如果信号是“部分开启”(比如0.4),你可以假设那是0。如果大部分开启(比如0.8),那么可以假设是1。如果你使用有10种可能状态的系统,就很难判断何时发生了错误。这是数字信号如此抗噪声的原因之一。
进制的其他例子
我们一直在使用其他进制,甚至动态变化的进制。我们通常不这么想:
小时、分钟、秒:1:32:04
- 我们知道这是1小时32分钟4秒。换算成秒就是(1 * 60 * 60) + (32 * 60) + 4。
英尺和英寸:3′ 5″
- 这是3英尺5英寸,即3 * 12 + 5英寸。
磅和盎司:8磅,5盎司
- 因为1磅等于16盎司,所以这是8 * 16 + 5盎司。我们一直在使用16进制数制!
结语
数字 10 在任何数制中意味着我们已经进位了一次基。例如, 10 在二进制中表示二, 10 在十进制中表示十,而 10 在十六进制中是十六。
如何区分这些数字,如何判断用了什么基?程序员通常会在 0b 二进制数字前加上。所以二进制中的2是
0b10
类似地,他们会写 0x 在十六进制数字前。所以十六进制中的16是:
0x10
如果没有符号(0b 或者 0x)在前面,我们就假设是十进制,一个普通数字。
现在去享受你的新知识吧!