逻辑位、乘法以及除法指令 — 位模式手术与乘除法的寄存器芭蕾
逻辑位、乘法以及除法指令 — 位模式手术与乘除法的寄存器芭蕾
这一章讲什么: 程序的组织学完了,本章转向「计算」本身。四件事: 位掩码(用 AND/OR/XOR 直接改写某个位)、移位(乘除 2 的幂的高速公路, 也是进制转换的主角)、乘法(imul 五种形态,以及为什么单操作数形态要霸占一对寄存器)、 除法(div/idiv 的隐式寄存器约定,和 C/Python 有符号除法规则之差)。 主线例子: 一个完整的往返——键盘敲下 "123",decToUInt 把它变成整数 123(用 imul); 加 123 得 246,intToUDec 再把 246 变回字符串 "246"(用 div)。 字符串与二进制之间怎么互相翻译,全在这两个函数里。
1. 位掩码:把数据当位模式,而不是当数
活教材:大小写字母只差一个位
ASCII 表里大小写字母的唯一区别是位 5(从右数第 6 位):1 是小写,0 是大写。
m = 0x6d = 0110 1101,M = 0x4d = 0100 1101——差的正是那个 32(0x20)1。
所以「转大写」不用减 32,也不用判断当前大小写,一张掩码 + 一次 AND 就完事:
掩码 = 1101 1111 = 0xdf ← 位 5 是 0,其余全是 1
0x6d ∧ 0xdf = 0x4d m → M
0x4d ∧ 0xdf = 0x4d M → M(大写的怎么按都还是大写)AND 的真值表决定了它的掩码语义:1 是「透明窗」(原样通过),0 是「抹除」。 由此推出三种标准手法,记住这一张表,位操作就全会了2:
| 目的 | 掩码怎么设 | 用哪条指令 |
|---|---|---|
| 把某位清 0 | 那位设 0,其余设 1 | AND(如 0xdf 转大写) |
| 把某位置 1 | 那位设 1,其余设 0 | OR |
| 把某位反转 | 那位设 1,其余设 0 | XOR |
toUpper 的 C 与汇编对照
C 版 toUpper(清单 16-3)对每个字符做 *destPtr = *srcPtr & UPMASK;,
指针各自 +1,直到撞上 NUL——循环骨架是第 13 章的,新东西只有那一个 &3。
gcc 的汇编(清单 16-4)里,掩码以立即数 −33 出现:and eax, -33——
−33 的补码恰好是 0xffffffdf,低 8 位 0xdf,效果一样4。
手写版(清单 16-6)用 al 直接处理字符,一个细节:操作 al 时 rax 的高 56 位保持原样,
所以只碰 al 是安全的——但别忘了循环终止用 cmp al, NUL,以及循环后把 NUL 也写进
目标串(忘了它是最经典的隐藏 bug:测试时碰巧下一个字节是 0 而蒙混过关,改天换个
长度就以随机方式暴雷)5。
顺带收两条指令卡:and / or(形态与 xor 同族,结果存目标;只设 SF/ZF/PF, OF、CF 清零)6。
2. 移位:乘除 2 的幂,与进制转换的发动机
核心事实:移一位 = 乘/除 2
把一个整数的所有位左移一位,等于乘 2;右移一位,等于除以 2—— 移位指令是机器上最快的乘除法,因为进位链本来就是硬件里现成的7。
主线例子第一站:hexToInt,"2a" 怎么变成 0x2a
程序读入十六进制字符串(如 "2a"),要把它变成 long int。算法对每个字符做两件事: 把 ASCII 字符转成 4 位整数,然后把 64 位累加值左移 4 位,腾出空当,OR 进新 4 位8:
读 '2':ASCII 0x32,本身就是数字字符,& 0x0f → 0x02
累加值: 0x00 << 4 | 0x02 = 0x02
读 'a':ASCII 0x61,比 '9' 大,先减 0x07 得 0x5a,& 0x0f → 0x0a
累加值: 0x02 << 4 | 0x0a = 0x2a ← 字符串 "2a" 现在是数 42两个掩码细节都值得停:减 0x07 补字母和数字之间的 ASCII 间隙('9' 是 0x39, 'A' 是 0x41,差 7);减完再 & 0x0f 取低 4 位——大小写无所谓, 因为 'a' 减完得 0x5a、'A' 减完得 0x3a,低 4 位都是 0x0a8。
移位指令家族:三个成员,两种右移
移位次数来自 cl 寄存器或立即数;32 位移位只用计数器的低 5 位,64 位用低 6 位9:
| 指令 | 方向 | 空出的位填什么 | 移出的末位去哪 | 典型用途 |
|---|---|---|---|---|
sal(= shl) | 左 | 右侧填 0 | CF | 乘 2、腾位 |
sar | 右(算术) | 左侧填最高位的副本(保号) | CF | 有符号 ÷2 |
shr | 右(逻辑) | 左侧填 0 | CF | 无符号 ÷2、取位 |
书里的「小心」一句话:sar 移负数永远移不成 0(−1 右移任意位还是 −1), 因为最高位的 1 会被无限复制——想要「越移越小直到 0」的直觉,那是 shr 的世界10。
movsx / movsxd:宽窄转换的两条桥
hexToInt 的 C 版要把 8 位的 current 和进 64 位累加值,编译器用了 movsx (符号扩展移动):把符号位(位 7)复制到目标的高 56 位。这里因为有 0x0f 掩码护体, 符号位必是 0,扩展无害;但若无掩码,movsx 与 movzx 的选择直接决定正负11。 配套还有 movsxd(32 位 → 64 位符号扩展)。三条桥合记: movzx 补 0、movsx 补符号、movsxd 专管 32→6411。
3. 乘法:imul 的五种形态与 rdx:rax 的「双人舞」
主线例子第二站:decToUInt,"123" 怎么变成 123
十进制串不能靠移位(10 不是 2 的幂),得真乘。算法:每读一个数字字符, 累加值 × 10,加上新数字12:
读 '1':0 × 10 + 1 = 1
读 '2':1 × 10 + 2 = 12
读 '3':12 × 10 + 3 = 123书里有个容易被问住的观察:转换的是 unsigned int,编译器却用了有符号的 imul。 为什么?看下面指令的语义就明白13。
imul:一个助记符,五种形态
imul(有符号乘法)可以带 1~3 个操作数14:
imul reg(单操作数):被乘数在 rax(按操作数宽度取 al/ax/eax/rax), 2n 位乘积摊在两个寄存器上:8 位 → ah:al,32 位 → edx:eax,64 位 → rdx:rax;imul reg1, reg2(双操作数):reg1 = reg1 × reg2,n 位 × n 位只留低 n 位;imul reg1, reg2, imm(三操作数):reg1 = reg2 × imm(imm 限 −128~+127)。
mul(无符号乘法)只有单操作数形态,寄存器约定同上,但高位不补符号14。 两表合一句话(表 16-1):乘数在「rax 或内存」,积的低位落回 rax 系、高位落 rdx 系—— 这两个寄存器从不出现在指令的操作数里,全靠约定15。
「高位丢了」的报警器:CF 和 OF
双/三操作数形态截断到 n 位时,若真积放得下,CF=OF=0;放不下,高位静默丢弃, CF=OF=1 报警——这是乘法版的「溢出标志」,和第 15 章 seto 正好接得上16。 回头看 decToUInt 之谜:只要积不超 32 位,imul 和 mul 的低 32 位结果完全相同 (补码的环性质),编译器顺手用形态更灵活的 imul,无必要再选 mul; 「无符号」是 main 里使用方式的事,与指令无关17。
手写版:三操作数 imul 的干净用法
清单 16-18 的手写 decToUInt 展示了最顺手的一式:imul ecx, ecx, DECIMAL
——累加值在 ecx,乘 10,结果回 ecx,一行搞定,无需碰 rdx:rax18。
4. 除法:div/idiv 的隐式约定与符号的坑
主线例子第三站:intToUDec,246 怎么变回 "246"
除法是乘法的逆运算,但多了余数这个「副产品」。C 版 intToUDec 的算法:
反复 digit = theInt % 10(余数,即最低位数字)、theInt /= 10(砍掉最低位),
数字逆序生成后再整体反转19。汇编版(清单 16-24)利用了一个关键事实:
一次 div 同时产出商和余数——商在 eax、余数在 edx,% 和 / 两个 C 运算符
背后是同一指令20。
246 ÷ 10:商 24(eax),余 6(edx)→ '6' 入串
24 ÷ 10:商 2, 余 4 → '4' 入串
2 ÷ 10:商 0, 余 2 → '2' 入串
商为 0,停;串是逆序的 "642",反转 → "246"div / idiv:被除数天生是 2n 位
除法指令永远拿一个 2n 位被除数除以 n 位除数:32 位除法里,被除数是 edx:eax 拼成的 64 位(edx 高 32 位 + eax 低 32 位),除数是指令的操作数; 商落 eax,余数落 edx——又是两个不出现在操作数里的寄存器(表 16-2)21。
经典事故由此而来:除之前必须按语义填满高位。
- div(无符号):把 edx 清零(
mov edx, 0或更省事的xor edx, edx); - idiv(有符号):要把符号位扩展进 edx——cdq 指令(eax → edx:eax 符号扩展, 同族还有 cbw/cwd/cqo,表 16-3)。忘了这步,−10 会被当成 0x00000000fffffff6 = 4294967286 来除,结果天差地别22。
两个附加条款:除数为 0、或商放不进目标寄存器,会触发异常(第 21 章细讲, 表现是操作系统一句没头没尾的错误消息杀掉程序);除完后所有标志位未定义, 别指望它们21。
有符号除法的语言地雷:C vs Python
指令只管向零截断;「负的商怎么取整」是语言政策,各语言不同。C:-27/4 = -6
(向零),余数 −3(随被除数);Python:-27//4 = -7(向下取整),余数 1(随除数)。
两者都满足 r = a − b×q,截断方向不同,余数的符号就跟着不同(表 16-4 四行对照)23。
作者的设计心得原话级别实用:「我在设计算法时尝试避免有符号除法,
并在计算结果后调整符号」——避开这个地雷场的最省事实践24。
尾声:除以常数的魔法
书里最后提了一笔优化界的经典技巧:除以 10 可以改写成
x/10 = (x × (2^n/10)) >> n——乘加移代替除法,因为移位远比除法快。
细节超出本书,但建议用 -O1 编译 intToUDec 自己看25。
这是「读懂编译器输出能白捡优化知识」的又一实证。
判断(我们的,不是书里的): 本章所有指令家族有个共同的教学法价值: 「隐式寄存器约定」是 x86 的传统艺能——mul/div 用 rdx:rax、 移位用 cl、字符串指令(本书未讲)用 rsi/rdi/rcx。 读懂这类代码的钥匙从来不是背操作数,而是背「谁和谁搭档、谁从不出现在操作数里」。 如果错,会错在: 这套约定是 x86 的历史包袱,ARM/RISC-V 的乘除干净得多 (显式三操作数,无隐式配对)——以 x86 学概念时,别把「隐式约定」当成计算机的常态。
判断(我们的,不是书里的): decToUInt/intToUDec 这对往返函数, 是全书最被低估的主线例子——它把第 2 章(ASCII/位模式)、第 3 章(算术)、 第 13 章(循环)、本章(掩码/移位/乘除)全部串成一条线,而且每个程序员每天都在用 (printf/scanf 内部就是这套)。学会这两百行,胜过背十张指令表。 如果错,会错在: 真实标准库的转换函数要处理溢出、空白、符号、locale 等 大量边界,教学版一概省略——拿它当「完整实现」会摔得很惨,当「机制演示」则刚刚好。
5. 作者的判断与证据
| 说法 | 性质 |
|---|---|
| 大小写转换 = 位 5;掩码三手法(清/置/反转) | ASCII 表事实 + 布尔代数,可验12 |
| 移位一位 = 乘除 2;移位快于乘除 | 机制事实,书以此作进制转换基础7 |
| sar 不移零、shr 才移零 | 指令语义,直接可验10 |
| imul 低 n 位对有/无符号通用;超宽则 CF=OF=1 | 补码性质 + 指令语义1617 |
| div 前忘清/扩 edx 是常见错误 | 作者点名的经典坑,机制可验22 |
| C 与 Python 3 的有符号除法规则对比 | 语言标准事实,书给了四行对照表23 |
| 「设计算法时避免有符号除法」 | 作者的个人工程经验24 |
| 除法慢、可用乘移代替 | 事实;书只给了思路没给细节25 |
| 「我不知道我的汇编比编译器效率高还是低,可读性远比效率重要」 | 作者的诚实声明,值得当座右铭26 |
6. 边界与局限
- 只覆盖整数乘除。 浮点乘除在第 19 章(SSE2),且本书不展开精度问题。
- 单操作数 mul 的高位语义只讲到「不扩符号」,双倍宽度乘积的实际用途(大数乘法) 没展开;idiv 的溢出异常只说「第 21 章」。
- 除以常数的魔法数优化只给式子不给推导——这是编译器构造的深水区, 想深入要看 Hacker's Delight 类文献(补充,不在书里)。
- 教学版转换函数不查输入合法性(非数字字符会算出垃圾),真实工程必须加校验。
7. 可带走的
- AND 掩码:0 抹除、1 通过;置位用 OR、反转用 XOR——一张掩码三手法;
- 大小写转换 =
& 0xdf(或| 0x20转小写),不用判断、不用减法; - 左移乘 2、右移除 2;sar 保号(填最高位副本)、shr 填 0;
- 进制转换的通用骨架:每读一字符 → 清成数值(掩码)→ 累加值腾位(移位或 ×radix)→ 并入;
- movzx 补 0 / movsx 补符号 / movsxd 32→64——宽窄转换三条桥;
- imul 五种形态:单操作数摊 rdx:rax,双/三操作数留低 n 位;mul 只有单操作数;
- 乘积超宽时 CF=OF=1 报警——编译器不替你查,乘大数前想想宽度;
- div/idiv:被除数 2n 位(edx:eax),商 eax、余数 edx,操作数只写除数;
- div 前
xor edx, edx;idiv 前 cdq(或 cbw/cwd/cqo)——忘了必错; - C 整数除法向零截断、余数随被除数;Python 向下取整、余数随除数——混用语言时先想这行;
- 能避开有符号除法就避开,算完再调符号;
- 除以常数可被编译器改写成乘+移位;想看就 -O1 再读汇编。
8. 原文地图
| 主题 | 原书章 | 原文位置 |
|---|---|---|
| 位 5 与大小写 | 第16 章 逻辑位、乘法以及除法指令 | text/22-ch16.txt:16(搜「位 5」) · text/22-ch16.txt:23(搜「0xdf」) |
| 掩码三手法 | 第16 章 逻辑位、乘法以及除法指令 | text/22-ch16.txt:26(搜「使某个位为 1」) |
| toUpper C 与汇编 | 第16 章 逻辑位、乘法以及除法指令 | text/22-ch16.txt:85(搜「清单 16-3」) · text/22-ch16.txt:120(搜「清单 16-4」) |
| NUL 尾巴的隐藏 bug | 第16 章 逻辑位、乘法以及除法指令 | text/22-ch16.txt:113(搜「恰好是 0x00」) |
| and / or 指令卡 | 第16 章 逻辑位、乘法以及除法指令 | text/22-ch16.txt:173(搜「逻辑 AND」) · text/22-ch16.txt:183(搜「逻辑 OR」) |
| 移位=乘除 2、hexToInt 算法 | 第16 章 逻辑位、乘法以及除法指令 | text/22-ch16.txt:331(搜「乘以 2」) · text/22-ch16.txt:391(搜「清单 16-9」) |
| sal / sar / shr 指令卡 | 第16 章 逻辑位、乘法以及除法指令 | text/22-ch16.txt:523(搜「算术左移」) · text/22-ch16.txt:532(搜「算术右移」) · text/22-ch16.txt:543(搜「逻辑右移」) |
| sar 不移零的警告 | 第16 章 逻辑位、乘法以及除法指令 | text/22-ch16.txt:540(搜「永远不会是 0」) |
| movsx / movsxd | 第16 章 逻辑位、乘法以及除法指令 | text/22-ch16.txt:501(搜「符号扩展移动」) · text/22-ch16.txt:510(搜「符号扩展双字移动」) |
| decToUInt 与 imul | 第16 章 逻辑位、乘法以及除法指令 | text/22-ch16.txt:739(搜「清单 16-15」) · text/22-ch16.txt:776(搜「清单 16-16」) |
| imul 五种形态 | 第16 章 逻辑位、乘法以及除法指令 | text/22-ch16.txt:835(搜「有符号乘法」) |
| mul 与 rdx:rax、表 16-1 | 第16 章 逻辑位、乘法以及除法指令 | text/22-ch16.txt:854(搜「无符号乘法」) · text/22-ch16.txt:878(搜「寄存器用法」) |
| CF=OF 报警 | 第16 章 逻辑位、乘法以及除法指令 | text/22-ch16.txt:853(搜「高位部分丢失」) |
| 有符号却用 imul 的解释 | 第16 章 逻辑位、乘法以及除法指令 | text/22-ch16.txt:897(搜「都是正确的」) |
| intToUDec 与 div | 第16 章 逻辑位、乘法以及除法指令 | text/22-ch16.txt:1084(搜「清单 16-21」) · text/22-ch16.txt:1129(搜「清单 16-22」) · text/22-ch16.txt:1379(搜「清单 16-24」) |
| idiv / div 指令卡 | 第16 章 逻辑位、乘法以及除法指令 | text/22-ch16.txt:1207(搜「有符号除法」) · text/22-ch16.txt:1219(搜「无符号除法」) |
| 除 0 与商过大 → 异常 | 第16 章 逻辑位、乘法以及除法指令 | text/22-ch16.txt:1230(搜「异常」) |
| cdq 等符号扩展指令、表 16-3 | 第16 章 逻辑位、乘法以及除法指令 | text/22-ch16.txt:1248(搜「保留被除数的符号」) · text/22-ch16.txt:1258(搜「符号扩展指令」) |
| C 与 Python 除法对比 | 第16 章 逻辑位、乘法以及除法指令 | text/22-ch16.txt:1213(搜「向零截断」) · text/22-ch16.txt:1283(搜「结果对比」) |
| 避免有符号除法 | 第16 章 逻辑位、乘法以及除法指令 | text/22-ch16.txt:1293(搜「尝试避免」) |
| 除法转乘移的魔法 | 第16 章 逻辑位、乘法以及除法指令 | text/22-ch16.txt:1442(搜「比乘法更耗时」) |
Footnotes
-
出处:「第16 章 逻辑位、乘法以及除法指令」第 14–25 段(
text/22-ch16.txt:16,搜「位 5」;text/22-ch16.txt:23,搜「0xdf」;text/22-ch16.txt:24,搜「0x6d ∧ 0xdf」)。 ↩ ↩2 -
出处:「第16 章 逻辑位、乘法以及除法指令」第 26–29 段(
text/22-ch16.txt:26,搜「使某个位为 1」;text/22-ch16.txt:28,搜「反转位」)。 ↩ ↩2 -
出处:「第16 章 逻辑位、乘法以及除法指令」第 85–117 段(
text/22-ch16.txt:99,搜「UPMASK」;text/22-ch16.txt:82,搜「destPtr」)。 ↩ -
出处:「第16 章 逻辑位、乘法以及除法指令」第 120–167 段(
text/22-ch16.txt:138,搜「and eax, -33」)。 ↩ -
出处:「第16 章 逻辑位、乘法以及除法指令」第 110–115 段(
text/22-ch16.txt:113,搜「恰好是 0x00」;text/22-ch16.txt:115,搜「看似随机的方式」)与第 311–318 段(手写版差异,text/22-ch16.txt:314,搜「高 56 位」)。 ↩ -
出处:「第16 章 逻辑位、乘法以及除法指令」第 173–192 段(
text/22-ch16.txt:173,搜「逻辑 AND」;text/22-ch16.txt:183,搜「逻辑 OR」;标志行为见第 182–182 段,text/22-ch16.txt:182,搜「OF 和 CF 标志被设为 0」)。 ↩ -
出处:「第16 章 逻辑位、乘法以及除法指令」第 329–332 段(
text/22-ch16.txt:331,搜「乘以 2」;text/22-ch16.txt:332,搜「效率非常高」)。 ↩ ↩2 -
出处:「第16 章 逻辑位、乘法以及除法指令」第 334–435 段(hexToInt 算法,
text/22-ch16.txt:414,搜「GAP」;text/22-ch16.txt:416,搜「INTPART」;text/22-ch16.txt:417,搜「<<4」;大小写无碍见第 429–432 段,text/22-ch16.txt:431,搜「都是一样的」)。 ↩ ↩2 -
出处:「第16 章 逻辑位、乘法以及除法指令」第 518–522 段(
text/22-ch16.txt:350,搜「#include <st」;text/22-ch16.txt:521,搜「低 5 位」;text/22-ch16.txt:522,搜「低 6 位」)。 ↩ -
出处:「第16 章 逻辑位、乘法以及除法指令」第 532–542 段(
text/22-ch16.txt:538,搜「最高位的副本」;text/22-ch16.txt:540,搜「永远不会是 0」)。 ↩ ↩2 -
出处:「第16 章 逻辑位、乘法以及除法指令」第 501–515 段(movsx,
text/22-ch16.txt:501,搜「符号扩展移动」)与第 510–515 段(movsxd,text/22-ch16.txt:510,搜「符号扩展双字移动」)。 ↩ ↩2 -
出处:「第16 章 逻辑位、乘法以及除法指令」第 689–767 段(decToUInt,
text/22-ch16.txt:760,搜「*intPtr = *intPtr * radix」;text/22-ch16.txt:761,搜「+= current」)。 ↩ -
出处:「第16 章 逻辑位、乘法以及除法指令」第 829–831 段(
text/22-ch16.txt:829,搜「无符号乘法指令 mul 和有符号乘法指令 imul」)。 ↩ -
出处:「第16 章 逻辑位、乘法以及除法指令」第 832–853 段(imul 指令卡,
text/22-ch16.txt:835,搜「有符号乘法」)与第 854–861 段(mul 指令卡,text/22-ch16.txt:854,搜「无符号乘法」)。 ↩ ↩2 -
出处:「第16 章 逻辑位、乘法以及除法指令」第 862–875 段(表 16-1,
text/22-ch16.txt:870,搜「rdx:rax」;text/22-ch16.txt:874,搜「永远不会作为操作数」)。 ↩ -
出处:「第16 章 逻辑位、乘法以及除法指令」第 851–853 段(
text/22-ch16.txt:852,搜「都设置为 0」;text/22-ch16.txt:853,搜「都设置为 1」)。 ↩ ↩2 -
出处:「第16 章 逻辑位、乘法以及除法指令」第 892–903 段(
text/22-ch16.txt:897,搜「都是正确的」;text/22-ch16.txt:829,搜「使用有符号乘法」;text/22-ch16.txt:903,搜「视为无符号整数」)。 ↩ ↩2 -
出处:「第16 章 逻辑位、乘法以及除法指令」第 906–1016 段(手写 decToUInt,
text/22-ch16.txt:997,搜「imul ❹ ecx, ecx, DECIMAL」)。 ↩ -
出处:「第16 章 逻辑位、乘法以及除法指令」第 1084–1126 段(intToUDec C 版,
text/22-ch16.txt:1106,搜「theInt % base」;text/22-ch16.txt:1109,搜「theInt / base」;反转见第 1122–1126 段,text/22-ch16.txt:1124,搜「逆序」)。 ↩ -
出处:「第16 章 逻辑位、乘法以及除法指令」第 1295–1296 段(
text/22-ch16.txt:1295,搜「两个独立的运算符」)与第 1379–1441 段(手写 intToUDec,text/22-ch16.txt:1413,搜「mov edx, 0」;text/22-ch16.txt:1414,搜「div r8d」)。 ↩ -
出处:「第16 章 逻辑位、乘法以及除法指令」第 1204–1247 段(div/idiv 指令卡与表 16-2,
text/22-ch16.txt:1209,搜「ax、dx:ax」;text/22-ch16.txt:1236,搜「寄存器用法」;忘设高位见第 1245–1247 段,text/22-ch16.txt:1245,搜「常见的编程错误」)。 ↩ ↩2 -
出处:「第16 章 逻辑位、乘法以及除法指令」第 1194–1202 段(清零 edx,
text/22-ch16.txt:1196,搜「必须放入 edx」)与第 1248–1256 段(idiv 的符号扩展与 cdq,text/22-ch16.txt:1249,搜「0xfffffff6」;text/22-ch16.txt:1258,搜「符号扩展指令」)。 ↩ ↩2 -
出处:「第16 章 逻辑位、乘法以及除法指令」第 1213–1281 段(
text/22-ch16.txt:1213,搜「向零截断」;text/22-ch16.txt:1283,搜「结果对比」;r = a − b×q 见第 1278 段,text/22-ch16.txt:1278,搜「r=a–b×q」)。 ↩ ↩2 -
出处:「第16 章 逻辑位、乘法以及除法指令」第 1293–1294 段(
text/22-ch16.txt:1293,搜「意想不到的结果」;text/22-ch16.txt:1293,搜「从以上讨论中可以看出,有」)。 ↩ ↩2 -
出处:「第16 章 逻辑位、乘法以及除法指令」第 1442–1454 段(
text/22-ch16.txt:1442,搜「比乘法更耗时」;text/22-ch16.txt:1453,搜「超出了本书的范围」)。 ↩ ↩2 -
出处:「第16 章 逻辑位、乘法以及除法指令」第 320–321 段(
text/22-ch16.txt:320,搜「效率是高还是低」;text/22-ch16.txt:320,搜「可读性」)。 ↩