【发布时间】:2015-08-24 06:39:38
【问题描述】:
如果我只有 32 位机器,cpu 是如何计算双精度数的?这个数字是 64 位宽的。 FPU 如何处理它?
更普遍的问题是,如何计算更宽的东西,然后是我的 alu。但是我完全理解整数方式。你可以简单地split他们。然而,对于浮点数,您有指数和尾数,应该以不同的方式处理。
【问题讨论】:
-
它只是比int64复杂,但可以处理2个32位数据。
如果我只有 32 位机器,cpu 是如何计算双精度数的?这个数字是 64 位宽的。 FPU 如何处理它?
更普遍的问题是,如何计算更宽的东西,然后是我的 alu。但是我完全理解整数方式。你可以简单地split他们。然而,对于浮点数,您有指数和尾数,应该以不同的方式处理。
【问题讨论】:
并非“32 位机器”中的所有内容都必须是 32 位。 x87 风格的 FPU 从一开始就不是“32 位”的,那是在 AMD64 创建之前的很长一段时间。它总是能够在 80 位扩展双精度上进行数学运算,而且它曾经是一个单独的芯片,所以根本没有机会使用主 ALU。
它比 ALU 更宽,是的,但它不通过 ALU,浮点单元使用它们自己的电路,这些电路尽可能宽。这些circuits 也比整数电路复杂得多,并且它们与组件中的整数 ALU 并没有真正重叠
【讨论】:
计算机体系结构中有几个不同的概念可以用比特来衡量,但它们都不能阻止处理 64 位浮点数。尽管这些概念可能相互关联,但对于这个问题,值得单独考虑它们。
通常,“32 位”表示地址为 32 位。这将每个进程的虚拟内存限制为 2^32 个地址。这是对程序产生最直接影响的度量,因为它影响指针的大小和内存中数据的最大大小。它与浮点数的处理完全无关。
另一个可能的含义是在内存和 CPU 之间传输数据的路径的宽度。这不是对数据结构大小的硬性限制——一个数据项可能需要多次传输。例如,Java 语言规范不需要double 或long 的原子加载和存储。见17.7. Non-Atomic Treatment of double and long。 double 可以使用两个单独的 32 位传输在内存和处理器之间移动。
第三个含义是通用寄存器大小。许多架构为浮点使用单独的寄存器。即使通用寄存器只有 32 位,浮点寄存器也可以更宽,或者可以将两个 32 位浮点寄存器配对来表示一个 64 位数字。
这些概念之间的典型关系是,具有 64 位内存地址的计算机通常会有 64 位通用寄存器,因此一个指针可以放在一个通用寄存器中。
【讨论】:
即使是 8 位计算机也提供扩展精度(80 位)浮点运算,通过编写代码进行计算。
现代 32 位计算机(x86、ARM、旧 PowerPC 等)具有 32 位整数和 64 位或 80 位浮点硬件。
【讨论】:
让我们先看看整数运算,因为它更简单。在您的 32 位 ALU 内部,有 32 个带有进位位的独立逻辑单元,它们会溢出链。 1 + 1 -> 10,进位但结转到第二个逻辑单元。整个 ALU 也将有一个进位输出,您可以使用它来进行任意长度的数学运算。但是宽度的唯一真正限制是您可以在一个周期中使用多少位。要进行 64 位数学运算,您需要 2 个或更多周期,并且需要自己执行进位逻辑。
【讨论】:
似乎问题只是“FPU 是如何工作的?”,而不考虑位宽。
FPU 做加法、乘法、除法等,每个都有不同的算法。
(也是减法)
给定两个带指数和尾数的数字:
m1 * 2 ^ e1
m2 * 2 ^ e2
,第一步是归一化:
m1 * 2 ^ e1
(m2 * 2 ^ (e2 - e1)) * 2 ^ e1(假设 e2 > e1)然后可以添加尾数:
(whatever) * 2 ^ e1
然后,应该将结果转换为有效的尾数/指数形式(例如,(无论)部分可能需要在 2^23 和 2^24 之间)。如果我没记错的话,这称为“重整化”。这里还应该检查溢出和下溢。
只需将尾数相乘并添加指数即可。然后重新归一化相乘的尾数。
对尾数执行“长除法”算法,然后减去指数。可能不需要重新规范化(取决于您如何实现长除法)。
将输入转换为范围 [0...π/2],然后对其运行 CORDIC 算法。
【讨论】: