研究一下 CPU 除法

在  QQ 群 里,    我 让 网友 馥岚过野  出题 来 考 我,

 

馥岚过野  说 :

你昨晚又说做汇编了

我问你几个问题:

目前CPU整数乘法和除法的性能差别在多少左右?

32位乘法和64位乘法有什么差别?

整数乘法时,大数和小数有没有区别?

 

 

2021-08-11  接着写  。

 

要 回答  这些问题,  我们先来 研究一下  计算机 的 除法 是 怎么实现 的  。

 

除法 就是 做 减法,  试商 一位,  除数 乘以 这一位 商,  由 被除数 来 减,   差 为 余数,   再 试商 下一位, 同样,  除数 乘以 这一位 商,  由 余数 来 减,    如此重复  。

 

这个 过程 用 逻辑电路  可以 实现 出来 ,   比如 :

                     

 

 

这个  计算过程 的 逻辑电路 可以设计 出来,   最 简单 的 设计 ,   每个 时钟周期 作 一次 试商,  比如 先 试商 1,  如果 1 乘以 除数 , 比 被除数 对应 的 前几位 小, 或 比 添位 后 的 余数 小,  则 试商 成功, 否则 试商 0  。

 

二进制 比较 简单,   每一位 最多 只要 试商 2 次,   0 和 1  。   也就是说,  每一位 最多 需要 2 次 试商,  也就是 2 个 时钟周期  。

 

对 被除数  的 每一位 最多 要 试商 2 次,    要 2 个 时钟周期,    能不能 在 一个 时钟周期 里,  就 完成 这 2 次 试商 ?

 

可以 。     这 可以用 组合逻辑电路 实现,   不用 时序逻辑电路,    也就是说,  除法  对 一位 的 (最多两次) 试商 都可以 由 一个 组合逻辑 电路 来 实现,   也就是在 一个  时钟周期 里 完成  。     这里 的 试商 包括了   试商 * 除数 再由 被除数(余数) 来 减 的 整个过程  。

 

这个 组合逻辑电路 的 模块电路图  可以 这样画 :

                 

 

 

这样,     每一位 的 (2 次)试商 可以 在 一个 时钟周期 里 完成  。

 

一个 8 位 的 二进制数,   除以一个 8 位 以内 的 二进制数,  看起来 要 对  8 个 位 试商  。

 

一开始,    第 1 次 试商 的 时候,    被除数 和 除数 * 试商  的 最高位 要 对齐,  再相减  。

 

之后,    余数 和 除数 * 试商  则 是  从 最低位 对齐,  再相减  。

 

实际上,    余数 要 添位 之后 才会和 除数 * 试商 相减  。   添位,  就是 给 余数 添上 当前 试商 的 被除数 的 那一位  。

 

有时候,     也 不用 添位,    直接 在 当前 试商 的 位 补 0  就行  。

 

为了叙述简便,    余数  添位 后 仍然 简称 余数,    大家 自行 理解 即可  。

 

 

使用 上面 这个 组合逻辑电路,    对 每一位 的 试商  需要 一个 时钟周期,   对  8 位 试商 需要  8 个 时钟周期,   也就是 做完一次 除法 需要  8 个 时钟周期  。

 

以此类推,   16 位 二进制数 的 除法 要  16 个 时钟周期,    32 位 的 除法 要  32 个 周期,    64 位 的 除法 要  64 个 周期  。

 

加法 减法 乘法 都 只要一个 时钟周期 ,    看起来 除法 成了   工作量  “大户”  了  。

 

能不能 缩短一些 时间,   也就是 减少一些 时钟周期 ?

 

能不能 在 一个 时钟周期 内  做完  8 位 的 试商  ?

 

可以,   同样,   这也就是用 一个   组合逻辑电路 来 完成 对 8 位 的 试商,    画 一个  模块电路图 :

                     

 

 

这个 图 没有 画完,  只 画 了 2 层  试商模块,  1 层 试商模块 负责 对  1 位 试商,   8 位 就要  8 层 试商模块  。

 

看的出来,   第 1 层 试商模块 是 2 个,   第 2 层 的 试商模块 个数 是 第 1 层 的 2 倍,   是 2 * 2 = 4 个,  下一层 是 上一层 的 2 倍 ,  也就是,

 

第 3 层 的 试商模块 个数 是  2 ³ = 8 个,

第 4 层 的 是  2 ⁴ = 16 个,

第 5 层 的 是  2 ⁵ = 32 个,

第 6 层 的 是  2 ⁶ = 64 个,

第 7 层 的 是  2 ⁷ = 128 个,

第 8 层 的 是  2 ⁸ = 256 个,

 

全部加起来 就是    2 + 4 + 8 + 16 + 32 + 64 + 128 + 256 = 512  个 试商模块  。    512 = 2 * 2 ⁸ ,    也就是   2 * 2 ⁸  个 试商模块 。

 

也就是,    n 位 二进制 整数 的 除法 要在 一个 时钟周期 里 完成,   需要   2 ^ ( n + 1 )  个 试商模块  。

 

这个 数量 是 很大的,    16 位 时,    2 * 2^16 = 131072  ≈  13 万 ,      32 位 时,   2 * 2^32 = 8 G  ≈  80 亿   。

 

13 万 个 试商模块,     这么多 电路元件  只是用于 除法,   这个 电路规模 是 很大 的,    80 亿 那就 更夸张 了  。

 

可以看到,    要想 在 一个 时钟周期 里 完成 比较多 位 的 除法,    需要 一个 规模 很大 的 组合逻辑电路 ,   规模 很大 就是 元件数量 很多  。

 

这些 与 硬件工艺 硬件资源 硬件成本  相关 。

 

总之 呢 ,   一个 时钟周期 完成 32 位 除法 是 不现实 的,     16 位 可能 也 够呛 ,   那么,  能不能 折中一点,    比如 一个 时钟周期 完成 4 位 除法,  这样,  8 位 除法 就是 8/4 = 2 个 周期, 16 位 除法 是 16/4 = 4 个周期,   32 位 除法 是 32/4 = 8 个周期,   64 位 除法 是 64 / 4 = 16 个 周期  。

 

应该 可以 这样做 ,  哈哈  。

 

 

上面的 是 基本 的 除法,   也可以说是 整数除法,    再来 看看  浮点数 的 除法  。

 

比如,   1001 / 0.0011 ,      首先 要 对齐 被除数 和 除数 的 小数点 ,  就是 把 被除数 和 除数 都 转换成 整数,    1001 / 0.0011 = 10010000 / 11 ,

 

1001 / 0.0011    会 转换成    10010000 / 11     来 计算  。

 

1001 是 4 位,  转换成  10010000 ,  就成了 8 位,  需要 8 位 的 存储单元 和 运算电路  。

 

对 二进制 来说,   余数 比 除数 至少 要 少一位,    如果 除数 是 4 位,  则 余数 可能是 3 位 、2 位 、1 位 、0 位  。

 

当然,    如果 试商 是 直接 补 0 ,   试商 * 除数 = 0 * 除数 = 0,    余数 - 试商 * 除数 = 余数 - 0 = 余数,    余数  还是 保持不变,    此时,  余数 也可能 和 除数 的 位数一样,  也就是,   余数 也可能 是 4 位  。

 

试商模块 处理 余数添位 和 余数 - 试商 * 除数,  余数 最多 4 位, 除数 最多 4 位 ;    试商 是 1 位,  二进制 的 话,   试商 只会 是 1 和 0 ,    试商 * 除数 也 只会 等于 除数 或  0,   也就是  试商 * 除数 最多 4 位,   所以 ,  试商模块 最多 只要 处理  4 位 数据 就可以,    也就是说,  试商模块 只要 4 位 电路 就可以 。

 

8 位 电路 应该 主要 是 存储 被除数 和 商 的 电路  。    但 4 位数 的 除法,   商 似乎 也 是 4 位,   所以,  商 似乎 也只要 4 位 的 存储单元  。

 

如果 是   1001 / 0.00000011  ,   那要 转换成  100100000000 / 11  ,   被除数 1001 要 变成   100100000000 ,    一个 12 位 整数,   需要  12 位 的 存储单元  。

 

实际 的 CPU 的 电路位数 是 有限 的,   设计 的 时候 会 决定 电路位数,   这 会对  浮点数 的 (大数)除法  精度 产生 相应 的 影响  。

 

比如,   电路 支持 的 位数 是 4 位,    则   1001 / 0.0011  转换成   10010000 / 11  ,    如果 被除数 的 存储单元 只有  4 位, 就 只会 存储  10010000  的  高 4 位 1001 ,  于是,  实际 的 除法 只会 做到 前 4 位 1001 除以 11,  商 的 后面位数 可能 直接 补 0  。

 

补 0 的 部分 和 实际 的 商 之间 就会 有 差,   这个 差 就是 丢失 的 精度  。

 

当然,   10010000 / 11   刚好 前 4 位  1001 / 11 = 11  就 可以 除尽, 后面 确实 补 0 就可以,  但 这 只是一个 例子,   如果 前 4 位 除不尽,  那  补 0 的 部分 和 实际 的 商 之间 就会 有 差 了  。

 

所以,  32 位 的 除法电路 的 被除数 存储单元 不一定 只有 32 位,   可能 是 更多位,   这样 可以 在 浮点数 大数除法  时 减少 精度丢失  。

 

 

小朋友们,   看了 上面的 计算机 除法 基础知识,    应该可以回答 开头 的 问题 了 吧  ?

 

等,   我现在 才 发现 ,   开头 的 3 个 问题 中,   只有 一个 提到了 除法,        这  ?

 

我 记得 看了 好几遍 题目 ,     这是 怎么回事  ?

 

 

我 提倡 用  模块电路图 + 模块规格  来 做  硬件电路 设计,     真的很爽,  爽死了,  无敌  。

 

模块规格 包括   模块 定义 、接口 、参数 等  。

 

 

 

 

posted on 2021-01-17 23:20  凯特琳  阅读(1027)  评论(0编辑  收藏  举报

导航