
什么是数制?
数制(或基数)定义了表示数字时可用的唯一数字个数。数字中的每个位置代表基数的幂。
计算中常见的四种数制是:基10(十进制)使用数字0-9,是日常使用的数字系统;基2(二进制)使用数字0-1,是计算机的语言;基16(十六进制)使用数字0-9和A-F,提供紧凑的二进制表示;基8(八进制)使用数字0-7,用于Unix文件权限。
相同的数值255在不同数制下的写法:
十进制: 255
二进制: 11111111
十六进制: FF
八进制: 377

为什么需要不同数制?
二进制(基2):硬件现实
数字电路本质上是二进制的——晶体管要么导通(1)要么截止(0)。所有计算机数据在硬件层面最终都是二进制。
十六进制(基16):紧凑的二进制
二进制很冗长。数字255需要8个二进制位,但只需要2个十六进制位。由于一个十六进制位恰好等于4个二进制位,十六进制是二进制的便捷简写。一个常见模式:1111 0100 1011 0101 变成十六进制的 F4B5。
十六进制在内存地址(0x7FFE42A3)、颜色代码(#FF5733)、SHA-256哈希(2cf24dba...)、IPv6地址(2001:0db8:...)、汇编语言以及调试中的字节表示中无处不在。

八进制(基8):Unix遗产
Unix文件权限使用八进制表示法,因为每个八进制位恰好代表3个二进制位(一组读/写/执行权限):
chmod 755 -> rwxr-xr-x
7 = 111 = rwx(所有者)
5 = 101 = r-x(组)
5 = 101 = r-x(其他)
转换过程
十进制转二进制
反复除以2,收集余数(从下往上读):
42 / 2 = 21 余 0
21 / 2 = 10 余 1
10 / 2 = 5 余 0
5 / 2 = 2 余 1
2 / 2 = 1 余 0
1 / 2 = 0 余 1
42 十进制 = 101010 二进制

二进制转十进制
将每一位乘以其位置值(2的幂):
101010 = 1x32 + 0x16 + 1x8 + 0x4 + 1x2 + 0x1
= 32 + 8 + 2 = 42
二进制转十六进制
从右向左每4位一组:
101010 -> 0010 1010 -> 2A
代码中的整数表示
// JavaScript
(255).toString(2) // "11111111" (二进制)
(255).toString(8) // "377" (八进制)
(255).toString(16) // "ff" (十六进制)
parseInt("FF", 16) // 255
parseInt("377", 8) // 255
parseInt("11111111", 2) // 255
// 字面量
0b11111111 // 二进制字面量 (255)
0o377 // 八进制字面量 (255)
0xFF // 十六进制字面量 (255)
bin(255) # '0b11111111'
oct(255) # '0o377'
hex(255) # '0xff'
int('ff', 16) # 255
int('11111111', 2) # 255
有符号整数表示
有符号整数使用补码编码。最高有效位(MSB)是符号位:0表示正数,1表示负数。要取反一个数,翻转所有位然后加1。
+42 的8位表示:00101010
-42 的8位表示:11010110(翻转42的位,然后+1)
这就是为什么8位有符号整数的范围是-128到127,而不是-127到127。
浮点数:另一个世界
整数数制不直接适用于浮点数。IEEE 754以二进制科学记数法存储数字:value = sign * mantissa * 2^exponent。这就是为什么0.1 + 0.2在大多数语言中不完全等于0.3——0.1和0.2没有精确的二进制表示。
-> 试试 整数进制转换器