32 位系统如何使用 80 位浮点?

mar*_*zzz 13 memory 32-bit

既然 32 位系统无法管理 2^33 的数字(因为明显的 32 位限制),那么如何管理80 位浮点数呢?

它应该需要“80位”...

Law*_*ceC 35

32 位 CPU 的含义之一是其寄存器为 32 位宽。这并不意味着它不能处理 64 位数字,只是它必须先处理较低的 32 位一半,然后再处理较高的 32 位一半。(这就是 CPU 具有进位标志的原因。)它比 CPU 仅将值加载到更宽的 64 位寄存器中要慢,但仍然可能。

因此,系统的“位数”不一定会限制程序可以处理的数字的大小,因为您总是可以将不适合 CPU 寄存器的操作分解为多个操作。因此它使操作变慢,消耗更多内存(如果您必须将内存用作“便签本”),并且更难以编程,但仍然可以进行操作。

但是,对于例如 Intel 32 位处理器和浮点,这些都无关紧要,因为 CPU 的浮点部分有自己的寄存器,并且它们的宽度为 80 位。(在 x86 的早期,浮点功能是一个单独的芯片,它从 80486DX 开始集成在 CPU 中。)


@Breakthrough 的回答激励我添加这个。

就浮点值存储在 FPU 寄存器中而言,它们的工作方式与二进制整数值非常不同。

浮点值的 80 位被分为尾数和指数(浮点数中也有“基数”,始终为 2)。尾数包含有效数字,指数确定这些有效数字的大小。所以没有“溢出”到另一个寄存器,如果你的数字太大而无法放入尾数,你的指数会增加并且你失去精度 - 即当你将它转换为整数时,你会失去右边的小数位 -这就是为什么它被称为浮点。

如果您的指数太大,则会出现浮点溢出,但由于指数和尾数被捆绑在一起,因此您无法轻松将其扩展到另一个寄存器。

我可能对其中一些内容不准确和错误,但我相信这就是它的要点。(这篇维基百科文章更简洁地说明了上述内容。)

这完全不同是可以的,因为 CPU 的整个“浮点”部分都在它自己的世界中 - 您使用特殊的 CPU 指令来访问它等等。此外,就问题而言,因为它是独立的,所以 FPU 的位数与本机 CPU 的位数并不紧密耦合。

  • 您从我的灵感中添加的所有内容都是正确的,所以不用担心:) 我应该提到一点,尽管您可以使用存在浮点单元的本机 CPU 指令,但您也可以在软件中执行浮点运算(具有等效的按位运算)或整数数学运算)。为了扩展到这一点,如果有足够的内存,您还可以使用软件算法/库(一种常用的算法/库)来获得 **任意精度数字**(与我们固定的 64 位或在这种情况下为 80 位相反) [GNU 多精度库](https://gmplib.org/))。 (4认同)
  • @markzzz:如果需要,没有什么是疯狂的。使用 16 位浮点数来模拟原子弹以评估您的核储备是疯狂的,因为它不够精确,您无法对结果充满信心。在这种情况下需要 32 位(是的,过去这些计算是在 16 位 PDP 上完成的)。同样,由于计算的混乱性质,使用 32 位 folats 来模拟气候不够精确。 (2认同)
  • FWIW,在没有您想要的大小的 FP 单元的机器上实现浮点运算的常用方法是使用整数指令在软件中进行。因为,在一天结束时,浮点数的指数和尾数都只是整数。正是我们解释它们的方式赋予了它们特殊的含义。 (2认同)
  • @PTwr 在 x86 上,您实际上有 7 个可用的 GPR 数据,包括 EBP。只是大多数语言实现的 ABI 都为堆栈帧指针保留了这个寄存器。但是例如使用 GCC,您可以使用`-fomit-frame-pointer` 来获取该寄存器。 (2认同)

Bre*_*ugh 13

32位、64位、128位都是指处理器的字长,可以认为是“基本数据类型”。通常,这是传入/传出系统 RAM 的位数,以及指针的宽度(尽管没有什么能阻止您使用软件访问比单个指针可以访问的更多的 RAM)。

假设一个恒定的时钟速度(以及架构中的其他一切都是恒定的),并假设内存读/写的速度相同(我们在这里假设 1 个时钟周期,但这与现实生活中的情况相去甚远),你可以在 64 位机器上的单个时钟周期内添加两个 64 位数字(如果计算从 RAM 中获取数字,则为三个):

ADDA [NUM1], [NUM2]
STAA [RESULT]
Run Code Online (Sandbox Code Playgroud)

我们也可以在 32 位机器上同样的计算……但是,在 32 位机器上,我们需要用软件来做,因为必须先添加低 32 位,补偿溢出,然后添加高 64 位:

     ADDA [NUM1_LOWER], [NUM2_LOWER]
     STAA [RESULT_LOWER]
     CLRA          ; I'm assuming the condition flags are not modified by this.
     BRNO CMPS     ; Branch to CMPS if there was no overflow.
     ADDA #1       ; If there was overflow, compensate the value of A.
CMPS ADDA [NUM1_UPPER], [NUM2_UPPER]
     STAA [RESULT_UPPER]
Run Code Online (Sandbox Code Playgroud)

通过我编写的汇编语法,您可以很容易地看到,在较低字长的机器上,更高精度的运算是如何花费指数级更长的时间的。这是 64 位和 128 位处理器的真正关键:它们允许我们在单个操作中处理更多的位。一些机器包括使用进位添加其他数量的指令(例如ADC在 x86 上),但上面的示例考虑了任意精度值。


现在,将这个问题扩展到这个问题,很容易看出我们如何添加大于可用寄存器的数字 - 我们只需将问题分解为寄存器大小的块,然后从那里开始工作。尽管正如@MatteoItalia所提到的,x87 FPU 堆栈原生支持 80 位数量,但在缺乏这种支持的系统中(或完全缺乏浮点单元的处理器!),等效的计算/操作必须在软件中执行。

因此,对于 80 位数字,在添加每个 32 位段之后,还要检查是否溢出到第 81 位,并可选择将高阶位清零。这些检查/归零是针对某些 x86 和 x86-64 指令自动执行的,其中指定了源和目标操作数的大小(尽管这些仅以 2 的幂从 1 个字节开始指定)。

当然,对于浮点数,不能简单地执行二进制加法,因为尾数和有效数字以偏移形式打包在一起。在 x86 处理器上的 ALU 中,有一个硬件电路可以为 IEEE 32 位和 64 位浮点数执行此操作;然而,即使没有浮点单元 (FPU),也可以在软件中执行相同的计算(例如,通过使用GNU 科学库,在架构上编译时使用 FPU,回退到软件算法如果没有可用的浮点硬件(例如对于缺少 FPU 的嵌入式微控制器))。

给定足够的内存,人们还可以对任意(或“无限”——在现实范围内)精度的数量进行计算,在需要更高的精度时使用更多的内存。GNU Multiple Precision library 中存在这种实现的一种实现,允许对整数、有理数和浮点运算进行无限精度(当然,直到您的 RAM 已满)。

  • 你没有提到最重要的细节:x86 平台上的 x87 FPU 有 80 位宽的浮点寄存器,所以它的本地计算实际上是在 80 位浮点数上完成的,不需要在软件中模拟任何东西。 (2认同)

Flo*_*ris 6

系统的内存架构可能只允许您一次移动 32 位 - 但这并不能阻止它使用更大的数字。

想想乘法。您可能知道高达 10x10 的乘法表,但在一张纸上执行 123x321 可能没有问题:您只需将其分解为许多小问题,将单个数字相乘,并处理进位等。

处理器可以做同样的事情。在“过去”,您有 8 位处理器可以进行浮点数学运算。但他们太慢了。


归档时间:

查看次数:

6624 次

最近记录:

8 年,8 月 前