Logo
Published on

2.2.进制

Authors
  • avatar
    Name
    xiaobai
    Twitter

1.进制的概念

核心思想:进制是一种计数和表示数字的方式,它规定了"逢几进一"。

我们最熟悉的是十进制,但在计算机世界里,二进制八进制十六进制扮演着至关重要的角色。

1.1.十进制

  • 基数:10
  • 数码:0, 1, 2, 3, 4, 5, 6, 7, 8, 9
  • 规则:逢十进一
  • 示例:数字 123 实际上是 1 * 10² + 2 * 10¹ + 3 * 10⁰

1.2.二进制

  • 基数:2
  • 数码:0, 1
  • 规则:逢二进一
  • 重要性:这是计算机硬件(CPU、内存)直接理解和处理的数据形式。所有数据在底层都是一串 0 和 1。
  • 示例:二进制数 1011 表示为: 1 * 2³ + 0 * 2² + 1 * 2¹ + 1 * 2⁰ = 8 + 0 + 2 + 1 = 11 (十进制)

1.3.八进制

  • 基数:8
  • 数码:0, 1, 2, 3, 4, 5, 6, 7
  • 规则:逢八进一
  • 特点:曾经在 Unix 系统权限管理中广泛使用,现在较少见。
  • 示例:八进制数 17 表示为: 1 * 8¹ + 7 * 8⁰ = 8 + 7 = 15 (十进制)

1.4.十六进制

  • 基数:16
  • 数码:0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E, F (其中 A=10, B=11, ..., F=15)
  • 规则:逢十六进一
  • 重要性极其常用。因为它与二进制有完美的对应关系(1位十六进制数对应4位二进制数),非常适合用来简化冗长的二进制表示,常用于表示内存地址、颜色值等。
  • 示例:十六进制数 1F 表示为: 1 * 16¹ + 15 * 16⁰ = 16 + 15 = 31 (十进制)

2.Python 中的进制操作

Python 提供了非常方便的内置函数来处理不同进制的数字。

2.1.表示不同进制的字面量

在代码中,你可以直接用特定前缀来表示不同进制的数字。

# 十进制 (Decimal) - 默认,无前缀)
dec_num = 100
print(dec_num)  # 输出: 100

# 二进制 (Binary) - 前缀 `0b` 或 `0B`
bin_num = 0b1100100 # 这就是十进制的 100
print(bin_num)      # 输出: 100 (Python会自动以十进制形式打印)

# 八进制 (Octal) - 前缀 `0o` 或 `0O`
oct_num = 0o144     # 这就是十进制的 100
print(oct_num)      # 输出: 100

# 十六进制 (Hexadecimal) - 前缀 `0x` 或 `0X`
hex_num = 0x64      # 这就是十进制的 100
print(hex_num)      # 输出: 100

2.2.进制转换函数

Python 有三个核心函数用于将十进制整数转换为其他进制的字符串

  • bin(i) -> 二进制字符串
  • oct(i) -> 八进制字符串
  • hex(i) -> 十六进制字符串
num = 255

# 转换为不同进制的字符串
bin_str = bin(num)
oct_str = oct(num)
hex_str = hex(num)

print(f"十进制 {num}:")
print(f"二进制  {bin_str}")  # 输出: 0b11111111
print(f"八进制  {oct_str}")  # 输出: 0o377
print(f"十六进制 {hex_str}")  # 输出: 0xff

注意:这些函数返回的是字符串,并且带有前缀。

2.3.将字符串转换为十进制整数

这是最强大的一个功能,使用 int() 函数。

int() 函数可以接受两个参数:

  • 第一个参数:要转换的字符串
  • 第二个参数 base:这个字符串所表示的数的进制(2-36)
# 将二进制字符串(不带前缀也可)转换为十进制
binary_string = "11111111"
# binary_string = "0b11111111" # 带前缀也可以
decimal_from_bin = int(binary_string, 2)
print(f"二进制 {binary_string} 是十进制 {decimal_from_bin}") # 输出: 255

# 将八进制字符串转换为十进制
octal_string = "377"
decimal_from_oct = int(octal_string, 8)
print(f"八进制 {octal_string} 是十进制 {decimal_from_oct}") # 输出: 255

# 将十六进制字符串转换为十进制
hex_string = "ff" # 大小写均可
# hex_string = "0xFF" # 带前缀也可以
decimal_from_hex = int(hex_string, 16)
print(f"十六进制 {hex_string} 是十进制 {decimal_from_hex}") # 输出: 255

# 甚至可以转换自定义进制的字符串,比如三进制
ternary_string = "100110"
decimal_from_ternary = int(ternary_string, 3)
print(f"三进制 {ternary_string} 是十进制 {decimal_from_ternary}") # 输出: 255 (1*3^5 + 1*3^2 + 1*3^1 = 255)

3.综合示例与应用场景

3.1.处理颜色值(RGB)

网页和图形编程中,颜色常用十六进制表示。

# 一个红色值
red_hex = "#FF0000"

# 提取出RGB分量并转换为十进制
red_component = int(red_hex[1:3], 16) # 取 ‘FF’, 以16进制解析
green_component = int(red_hex[3:5], 16) # 取 ‘00’
blue_component = int(red_hex[5:7], 16) # 取 ‘00’

print(f"颜色 {red_hex} 的RGB分量为:")
print(f"  R: {red_component}")
print(f"  G: {green_component}")
print(f"  B: {blue_component}")
# 输出:
# R: 255
# G: 0
# B: 0

3.2.格式化输出(去掉前缀)

有时我们不需要 0b0x 这样的前缀。

num = 42

# 方法1:使用字符串切片
hex_with_prefix = hex(num) # 0x2a
hex_without_prefix_1 = hex_with_prefix[2:] # 从第2个字符开始截取 2a
print(hex_without_prefix_1)#2a

# 方法2:使用格式化字符串 (f-string) - 更推荐!
# 格式: `:x` 表示十六进制, `:b` 表示二进制, `:o` 表示八进制
hex_without_prefix_2 = f"{num:x}" # 小写
hex_without_prefix_3 = f"{num:X}" # 大写
bin_without_prefix = f"{num:b}"

print(hex_without_prefix_2) # 输出: 2a
print(hex_without_prefix_3) # 输出: 2A
print(bin_without_prefix)   # 输出: 101010

4.总结

进制规则Python 前缀转换函数应用场景
十进制逢十进一int("123")人类日常计算
二进制逢二进一0bbin()计算机底层逻辑、位运算
八进制逢八进一0ooct()历史遗留(如Linux文件权限)
十六进制逢十六进一0xhex()内存地址、颜色代码、数据包

核心要点

  1. 在计算机内存中,所有数据最终都是二进制
  2. Python 中,带前缀的数字(如 0xff)在解释时会被直接转换为十进制整数对象。
  3. bin(), oct(), hex() 用于将数字变成字符串
  4. int(str, base) 用于将字符串解析为数字,是逆向转换的万能钥匙。
  5. 熟练使用 f-string 的格式化功能可以方便地控制输出格式。

5.以下内容不用看,Python全部学完后再看

6.比特、字节与存储单位

6.1.核心概念:比特与字节

6.1.1.1. 比特(Bit)

  • 英文:Bit (Binary Digit)
  • 含义:计算机中最小的数据单位,代表一个二进制位
  • 数值:只能是 01
  • 类比:可以把它想象成一个开关,要么开(1),要么关(0)
  • 重要性:所有数据在计算机底层都是以比特流(一串0和1)的形式存储和处理的
# 一个数字在内存中的比特表示
num = 65
binary = bin(num)  # 0b1000001
print(f"数字 {num} 的二进制表示:{binary}")
print(f"占用 {len(binary) - 2} 个比特位")  # 减去 '0b' 前缀

6.1.2.2. 字节(Byte)

  • 英文:Byte
  • 含义:计算机中最基本的内存寻址单位数据计量单位
  • 换算1 字节 = 8 比特(1 Byte = 8 bits)
  • 重要性:一个字节可以表示一个字符(比如英文字母、数字、标点)。早期的编码系统(如 ASCII)就是用 1 个字节(8 位)来定义一个字符的
  • 表示范围:1 个字节可以表示 (2^8 = 256) 个不同的值(0-255)
# 字符与字节
char = 'A'
print(f"字符 '{char}' 的 ASCII 码:{ord(char)}")  # 65
print(f"二进制表示:{bin(ord(char))}")  # 0b1000001
print(f"占用:1 个字节(8 个比特)")

# 字符串的字节长度
text = "Hello"
bytes_data = text.encode('utf-8')
print(f"\n字符串 '{text}' 占用 {len(bytes_data)} 个字节")

# 查看每个字节
print("每个字节的值:", [byte for byte in bytes_data])
# [72, 101, 108, 108, 111] - 对应 H e l l o 的 ASCII 码

6.2.存储单位:二进制前缀

由于计算机使用二进制,其单位换算通常是 1024 ((2^10)) 倍,而不是国际单位制(SI)的 1000 倍。为了区分,有专门的二进制前缀。

单位名称缩写换算关系字节数示例与应用
字节B基础单位1一个英文字符
千字节KiB1 KiB = 1024 B1,024一小段文本、小图标
兆字节MiB1 MiB = 1024 KiB1,048,576一首 MP3 歌曲、高清照片
吉字节GiB1 GiB = 1024 MiB1,073,741,824高清电影、大型软件
太字节TiB1 TiB = 1024 GiB1,099,511,627,776个人电脑硬盘、大型数据库
拍字节PiB1 PiB = 1024 TiB(2^50)大型数据中心
艾字节EiB1 EiB = 1024 PiB(2^60)全球互联网流量

注意:在很多非正式的场合,人们仍然习惯使用 KB, MB, GB 来表示 1024 的倍数,但从技术标准上讲,KiB, MiB, GiB 才是准确的。

6.3.网络与速度单位:十进制前缀

在网络和通信领域,通常使用标准的国际单位制(SI)前缀,即 1000 倍率。

单位名称缩写换算关系应用场景
比特每秒bps (b/s)基础单位网络带宽、传输速率
千比特每秒Kbps (Kb/s)1 Kbps = 1,000 bps旧的拨号网络
兆比特每秒Mbps (Mb/s)1 Mbps = 1,000 Kbps现代家庭宽带、Wi-Fi
吉比特每秒Gbps (Gb/s)1 Gbps = 1,000 Mbps高速光纤、数据中心
太比特每秒Tbps (Tb/s)1 Tbps = 1,000 Gbps国家级骨干网络

6.3.1.重要区别:Byte vs. bit

这是最容易混淆的地方!

  • Byte (B,大写)字节,用于表示存储容量(文件大小、硬盘容量、内存大小)
  • bit (b,小写)比特,用于表示传输速度(网络带宽、下载速度)

换算1 Byte = 8 bits

6.3.2.实际应用举例

你的家庭宽带是 100 Mbps(100 兆比特每秒)。那么理论最大下载速度是多少 MB/s(兆字节每秒)?

100 Mbps = 100,000,000 bits per second
100,000,000 bps ÷ 8 = 12,500,000 Bps ≈ 12.5 MB/s

所以,当你用下载工具时,显示的最高速度大概在 12.5 MB/s 左右。

6.4.Python 中的单位处理

Python 本身不内置单位转换,但我们可以轻松编写函数来计算。

6.4.1.格式化文件大小

这个函数可以将字节数转换成人类易读的格式(使用二进制前缀)。

def format_file_size(size_in_bytes):
    """
    将字节数格式化为人类可读的字符串 (使用二进制前缀 KiB, MiB 等)
    
    参数:
        size_in_bytes: 文件大小(字节)
    返回:
        格式化后的字符串
    """
    # 定义单位阶梯
    units = ['B', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB']
    size = float(size_in_bytes)
    index = 0

    # 循环除以1024,直到找到合适的单位
    while size >= 1024 and index < len(units) - 1:
        size /= 1024.0
        index += 1

    # 格式化输出,保留2位小数
    return f"{size:.2f} {units[index]}"

# 测试不同大小的文件
file_sizes = [
    500,                # 500 字节
    1536,               # 1.5 KiB
    1048576,            # 1 MiB
    3221225472,         # 3 GiB
    1099511627776       # 1 TiB
]

print("文件大小转换示例:")
for size in file_sizes:
    print(f"{size:>15} 字节 = {format_file_size(size)}")

# 输出:
#             500 字节 = 500.00 B
#            1536 字节 = 1.50 KiB
#         1048576 字节 = 1.00 MiB
#      3221225472 字节 = 3.00 GiB
#   1099511627776 字节 = 1.00 TiB

6.4.2.网络速度换算

def mbps_to_mb_per_second(mbps_speed):
    """
    将网络速度从 Mbps (兆比特/秒) 转换为 MB/s (兆字节/秒)
    
    参数:
        mbps_speed: 网络带宽(Mbps)
    返回:
        下载速度(MB/s)
    """
    mb_per_second = mbps_speed / 8.0
    return mb_per_second

# 测试不同的宽带速度
bandwidths = [50, 100, 300, 500, 1000]  # 常见的宽带速度

print("\n网络带宽与下载速度对照表:")
print("-" * 50)
print(f"{'带宽':<10} {'理论最大下载速度':<20}")
print("-" * 50)

for bw in bandwidths:
    download_speed = mbps_to_mb_per_second(bw)
    print(f"{bw:>6} Mbps -> {download_speed:>8.2f} MB/s")

# 输出:
# 网络带宽与下载速度对照表:
# --------------------------------------------------
# 带宽         理论最大下载速度        
# --------------------------------------------------
#     50 Mbps ->     6.25 MB/s
#    100 Mbps ->    12.50 MB/s
#    300 Mbps ->    37.50 MB/s
#    500 Mbps ->    62.50 MB/s
#   1000 Mbps ->   125.00 MB/s

6.4.3.下载时间计算

def calculate_download_time(file_size_mb, bandwidth_mbps):
    """
    计算文件下载所需时间
    
    参数:
        file_size_mb: 文件大小(MB)
        bandwidth_mbps: 网络带宽(Mbps)
    返回:
        下载时间(秒)
    """
    # 将文件大小转换为 Mb (兆比特)
    file_size_mb_bits = file_size_mb * 8
    
    # 计算时间(秒)
    time_seconds = file_size_mb_bits / bandwidth_mbps
    
    return time_seconds

# 测试:下载一个 2GB 的电影
file_size = 2 * 1024  # 2048 MB
bandwidths = [50, 100, 300, 1000]

print("\n下载 2GB 电影所需时间:")
print("-" * 50)

for bw in bandwidths:
    time_sec = calculate_download_time(file_size, bw)
    time_min = time_sec / 60
    
    if time_min < 1:
        print(f"{bw:>4} Mbps: {time_sec:.1f} 秒")
    else:
        print(f"{bw:>4} Mbps: {time_min:.1f} 分钟 ({time_sec:.0f} 秒)")

# 输出示例:
#  50 Mbps: 5.5 分钟 (327 秒)
# 100 Mbps: 2.7 分钟 (164 秒)
# 300 Mbps: 54.6 秒
# 1000 Mbps: 16.4 秒

6.4.4.比特操作

# 查看一个数字的比特表示
def show_bits(number, byte_count=1):
    """显示数字的比特表示"""
    # 转换为二进制字符串(去掉 0b 前缀)
    binary = bin(number)[2:]
    
    # 填充到指定字节数
    total_bits = byte_count * 8
    binary = binary.zfill(total_bits)
    
    # 格式化输出(每8位一组)
    formatted = ' '.join([binary[i:i+8] for i in range(0, len(binary), 8)])
    
    print(f"数字 {number} 的比特表示:")
    print(f"  二进制: {formatted}")
    print(f"  占用: {byte_count} 字节 ({total_bits} 比特)")

# 测试
show_bits(65, 1)   # 字符 'A'
print()
show_bits(255, 1)  # 最大的单字节数
print()
show_bits(1024, 2) # 需要2个字节

# 输出:
# 数字 65 的比特表示:
#   二进制: 01000001
#   占用: 1 字节 (8 比特)
# 
# 数字 255 的比特表示:
#   二进制: 11111111
#   占用: 1 字节 (8 比特)
# 
# 数字 1024 的比特表示:
#   二进制: 00000100 00000000
#   占用: 2 字节 (16 比特)

6.5.常见误区与注意事项

概念单位关键点常见误区
最小单位比特 (bit, b)0 或 1与字节混淆
基本单位字节 (Byte, B)1 Byte = 8 bits忘记大小写区别:B ≠ b
存储容量KiB, MiB, GiB以 1024 为进制硬盘厂商用 1000 进制,所以标称 1TB 的硬盘在系统里显示约 931GiB
网络速度Mbps, Gbps以 1000 为进制,单位是 bit误将 100 Mbps 宽带认为是 100 MB/s 的下载速度(实际约 12.5 MB/s)

6.5.1.1. 硬盘容量的"缩水"现象

# 为什么 1TB 硬盘实际只有 931GB?
advertised_tb = 1  # 厂商标称 1TB
advertised_bytes = advertised_tb * 1000 * 1000 * 1000 * 1000  # 厂商用1000进制

# 转换为系统显示的容量(1024进制)
actual_gib = advertised_bytes / (1024 ** 3)

print(f"厂商标称: {advertised_tb} TB")
print(f"实际容量: {advertised_bytes:,} 字节")
print(f"系统显示: {actual_gib:.2f} GiB")

# 输出:
# 厂商标称: 1 TB
# 实际容量: 1,000,000,000,000 字节
# 系统显示: 931.32 GiB

6.5.2.2. 大小写的重要性

# 小心大小写!
print("Byte (B,大写) = 字节,用于存储容量")
print("bit (b,小写) = 比特,用于传输速度")
print()
print("100 MB = 100 兆字节 = 800 兆比特 = 800 Mb")
print("100 Mb = 100 兆比特 = 12.5 兆字节 = 12.5 MB")

6.6.核心记忆点

  1. B 和 b 差 8 倍
    • 1 Byte (B) = 8 bits (b)
    • 大写 B = 字节,小写 b = 比特
  2. 存储容量使用 Byte
    • 文件大小、硬盘容量、内存大小
    • 单位:B, KiB, MiB, GiB, TiB
    • 进制:1024
  3. 网络速度使用 bit
    • 网络带宽、下载速度
    • 单位:bps, Kbps, Mbps, Gbps
    • 进制:1000
  4. 速度换算公式
    • 下载速度 (MB/s) = 带宽 (Mbps) ÷ 8
    • 100 Mbps 宽带 ≈ 12.5 MB/s 下载速度
  5. 硬盘容量"缩水"
    • 厂商用 1000 进制(1TB = 1000GB)
    • 系统用 1024 进制(1TiB = 1024GiB)
    • 1TB ≈ 931GiB

6.7.实用小工具

class StorageConverter:
    """存储单位转换工具类"""
    
    @staticmethod
    def bytes_to_human(bytes_count, binary=True):
        """将字节转换为人类可读格式"""
        if binary:
            units = ['B', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB']
            base = 1024
        else:
            units = ['B', 'KB', 'MB', 'GB', 'TB', 'PB']
            base = 1000
        
        size = float(bytes_count)
        for unit in units[:-1]:
            if abs(size) < base:
                return f"{size:.2f} {unit}"
            size /= base
        return f"{size:.2f} {units[-1]}"
    
    @staticmethod
    def mbps_to_mbytes(mbps):
        """将 Mbps 转换为 MB/s"""
        return mbps / 8
    
    @staticmethod
    def mbytes_to_mbps(mbytes):
        """将 MB/s 转换为 Mbps"""
        return mbytes * 8

# 使用示例
converter = StorageConverter()

# 转换文件大小
print(converter.bytes_to_human(1536000000))  # 1.43 GiB
print(converter.bytes_to_human(1536000000, binary=False))  # 1.54 GB

# 转换网速
print(f"100 Mbps = {converter.mbps_to_mbytes(100):.2f} MB/s")
print(f"12.5 MB/s = {converter.mbytes_to_mbps(12.5):.0f} Mbps")
img