32位机器如何计算双精度数

How does a 32-bit machine compute a double precision number

如果我只有 32 位机器,cpu 如何计算双精度数?这个数字是 64 位宽。 FPU 是如何处理的?

更一般的问题是,如何计算比我的 alu 更宽的东西。但是我完全理解整数方式。您只需 split 即可。然而对于浮点数,你有指数和尾数,应该以不同的方式处理。

即使是 8 位计算机也提供扩展精度(80 位)浮点运算,通过编写代码来进行计算。

现代 32 位计算机(x86、ARM、较旧的 PowerPC 等)具有 32 位整数和 64 或 80 位浮点硬件。

并非“32 位机器”中的所有内容都必须是 32 位的。 x87 风格的 FPU 从一开始就不是“32 位”的,那是在 AMD64 出现之前的很长时间。它总是能够在 80 位扩展双精度上进行数学运算,并且它曾经是一个单独的芯片,所以根本没有机会使用主 ALU。

是的,它比 ALU 宽,但它不通过 ALU,浮点单元使用它们自己的电路,它们的宽度与它们需要的一样宽。这些circuits也比整数电路复杂得多,而且它们在组件中并没有真正与整数ALU重叠

我们先看整数运算,因为它更简单。在你的 32 位 ALU 内部,有 32 个带有进位位的独立逻辑单元,它们会向上溢出链。 1 + 1 -> 10,进位但结转到第二个逻辑单元。整个 ALU 也会有一个进位位输出,你可以用它来做任意长度的数学运算。 but 宽度的唯一真正限制是在一个周期内可以使用多少位。要进行 64 位数学运算,您需要 2 个或更多周期,并且需要自己执行进位逻辑。

看来问题只是"how does FPU work?",与位宽无关

FPU做加法、乘法、除法等,每个都有不同的算法。

加法

(也是减法)
给定两个带指数和尾数的数字:

  • x1 = m1 * 2 ^ e1
  • x2 = m2 * 2 ^ e2

,第一步归一化:

  • x1 = m1 * 2 ^ e1
  • x2 = (m2 * 2 ^ (e2 - e1)) * 2 ^ e1(假设 e2 > e1)

然后可以加上尾数:

  • x1 + x2 = (whatever) * 2 ^ e1

然后,应将结果转换为有效的 mantissa/exponent 形式(例如,(任何)部分可能需要介于 2^23 和 2^24 之间)。如果我没记错的话,这叫做 "renormalization" 。这里还应该检查上溢和下溢。

乘法

只需将尾数相乘并加上指数即可。然后将相乘后的尾数重新归一化。

对尾数进行"long division"算法,然后减去指数。可能不需要重新归一化(取决于您如何实现长除法)。

Sine/Cosine

将输入转换为范围 [0...π/2],然后 运行 CORDIC 算法就可以了。

等等

计算机体系结构中有几个不同的概念可以用位来衡量,但其中 none 无法处理 64 位浮点数。虽然这些概念可能是相关的,但对于这个问题还是值得单独考虑的。

通常,“32 位”意味着地址是 32 位。这将每个进程的虚拟内存限制为 2^32 个地址。它是对程序产生最直接影响的度量,因为它会影响指针的大小和内存数据的最大大小。与浮点数的处理完全无关

另一个可能的含义是内存和 CPU 之间传输数据的路径宽度。这不是对数据结构大小的硬性限制——一个数据项可能需要多次传输。例如,Java 语言规范不需要原子加载和存储 doublelong。参见 17.7. Non-Atomic Treatment of double and longdouble 可以使用两个单独的 32 位传输在内存和处理器之间移动。

第三个含义是通用寄存器大小。许多体系结构对浮点数使用单独的寄存器。即使通用寄存器只有 32 位,浮点寄存器可以更宽,或者可以将两个 32 位浮点寄存器配对来表示一个 64 位数字。

这些概念之间的典型关系是,具有64位内存地址的计算机通常具有64位通用寄存器,因此一个指针可以容纳一个通用寄存器。