Chapter 2. Representing and Manipulating Information¶
约 1159 个字 57 行代码 预计阅读时间 7 分钟
Part 1. 信息的存储¶
通常情况下,程序将内存看作一个大数组,数组的元素长度为一个字节,每个元素都有唯一的地址 (address) ,这些所有地址的集合就称为 虚拟地址空间 (virtual address space)
字长决定了虚拟空间地址的范围,例如,对于一个 w bit word 的机器,虚拟地址的范围是 \(0\) ~ \(2^w-1\)
Tip
现如今,大部分服务器、PC、手机都完成了从32位字长到64字长的迁移;不过在一些嵌入式的场景中,32位机器仍占有一席之地
在迁移过程中,大部分64位机器做了向后兼容,因此64位机器仍然可以运行由32位机器编译的程序;同时,可以在64机器上通过指令 gcc hello.c -m32 -o hello32
编译能够在32位机器上运行的程序
以 C语言 为例子,将整型变量 (占用四字节) 0x01234567
存储到内存中,根据存储方式的不同,有如下两种内存结构:
大多数 Intel 兼容机采取小端模式,IBM和Sum公司的机器大多采用大端法
二进制是计算机编码、存储和操作信息的核心,围绕着0和1的研究已经演化出丰富的数学知识体系。
关于布尔运算,在离散数学、数字逻辑设计等课程均有详细讲解,此处亦不再赘述
Masking Operation
掩码运算,例如希望得到 0x12ABCDEF
的最低有效字节的值,可以通过 0x12ABCDEF & 0xFF
来得到结果
移位运算补充:
- 逻辑右移
- 空位补充
0
- 空位补充
- 算数右移
- 空位与最高有效位相同
实际上,几乎所有编译器对有符号数的右移均采用算数右移;而对于无符号数,一定是逻辑右移
Part 2. 整数的表示¶
源码、反码、补码... 老生常谈,此处亦不细讲,仅补充几点额外的信息:
- 对于大多数C语言实现,有符号数和无符号数之间转换的规则是,位模式不变,但是解释这些位的方法变了
- 如果一个运算数是有符号数,另一个是无符号数,那么C语言会隐式的将有符号数强制转化为无符号数进行运算
- 当位数更多的数据类型转化为位数更低的数据类型时,多出的位数舍去;当位数低的数据类型转化为位数高的数据类型时,需要根据要转化成的数据是否是有符号数
- 若是无符号数,新增位全为
0
- 若是有符号数
- 若是正数,新增位全为
0
- 若是负数,新增位全为
1
- 若是正数,新增位全为
- 若是无符号数,新增位全为
- 保证符号拓展数值保持不变
Part 3. 整数运算¶
你知道我要说什么,这节内容在 《数字逻辑设计》 中亦有记载
- 无符号数加法的溢出
- 对于两个 w 位的无符号数的乘法,得到的结果也应该为 w 位,因此有可能会产生截断
- 无论是无符号乘法还是补码乘法,运算结果的位级表示都是一样的(截断后)
- 同样的,除法可以看作是右移操作。对于有符号的负数的算数右移,由于需要满足四舍五入的特性,需要对原数加上 \(2^k-1\) 大小的
bias
,即可得到向零舍入的结果
Part 4. 浮点数¶
浮点数可以分为三类:
- Normalized Values
- Denormalized Values
- Special Values
exp
全为 1- 特殊值也分两类:
- 一类是无穷大
frac
全为 0 为无穷大(正负号看s
)
- 另一类表示 "不是一个数(NaN)"
frac
不全为 0 则为 Not a Number
- 一类是无穷大
Rount-to-even
为什么出现向偶数舍入的统计方法?因为统一向上取整或向下取整会导致向上或向下的偏差,但是向偶数舍入 (仅中间值向偶数舍入,其它值四舍五入) 的误差会比较小。