32位系统如何使用80位浮点?[重复]


13

由于32位系统无法管理2 ^ 33的数字(由于明显的32位限制),如何管理80位浮点数

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


8
以相同的方式处理64位浮点数。它使用3或(2)个32位寄存器。由于80位浮点数甚至都不是标准大小,因此它实际上是一个96位数字,只使用80位。
拉姆猎犬,2014年

5
当您担心平台紧张时,您会担心CPU的内部工作,就像其他人所说的那样,并且指令在系统上本机运行的方式也是如此。IEEE754编号通常可以在CPU的FPU执行单元中直接处理,而128位编号则需要使用已编程的多个指令,以便它们可以汇总应用程序正在评估的值的含义。剩下的数字处理由应用程序决定。
弗兰克·托马斯

2
@Ƭᴇcʜιᴇ007不是相当欺骗一个。那是关于数字与其文本/ ASCII表示形式之间差异的更多信息,尽管其中一些答案也可以解决这个问题。
鲍勃

3
在几乎所有现代机器中,浮点都是由单独的处理器处理的(尽管通常与主处理器在同一芯片上)。所有这些处理器都知道如何处理80位(尽管有些处理器的处理速度比其他处理器快得多)。(而且处理器的“宽度”无论如何都是虚构的。
Daniel R Hicks

6
@Ramhound:不,80位是8087的特性,它使用1个FP寄存器。绝对不是96位数字。
MSalters 2014年

Answers:


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的位数并不紧密相关。


4
您从我的灵感中添加的所有内容都是正确的,因此不用担心:)我只想提一点,尽管您可以使用存在浮点单元的本机CPU指令,但也可以在软件中执行浮点运算(等效于按位运算)或整数数学运算)。要扩展到这一点,只要有足够的内存,您还可以使用软件算法/库(任意一种是GNU多精度)来获得任意精度的数字(与本例中固定的64位或80位相对)图书馆)。
2014年

1
鸡蛋里挑骨头:第一Intel集成FPU是在80486DX,而不是80386
spudone

2
@markzzz:如果需要的话,没有什么是疯狂的。使用16位浮点数模拟原子弹以评估您的核储备之所以疯狂,是因为它不够精确,不足以使您对结果充满信心。在这种情况下,需要32位(是的,过去,这些计算是在16位PDP上完成的)。同样,由于计算的混乱性,使用32位folat模拟气候并不十分精确。
slebetman 2014年

2
FWIW是在没有所需大小的FP单位的机器上实现浮点运算的常用方法是使用整数指令在软件中进行。因为在一天结束时,浮点数的指数和尾数都只是整数。这就是我们解释它们的方式,从而赋予了它们特殊的含义。
slebetman 2014年

2
x86上的@PTwr实际上包含7个可用的GPR,包括EBP。只是大多数语言实现中的ABI都会将此寄存器保留为堆栈帧指针。但是,例如,在GCC中,您可以-fomit-frame-pointer用来取回该寄存器。
Ruslan

13

32位,64位和128位均指处理器的字长,可以将其视为“基本数据类型”。通常,这是传输到系统RAM或从系统RAM传输的位数,以及指针的宽度(尽管没有什么可以阻止您使用软件访问比单个指针可以访问的更多的RAM)。

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

ADDA [NUM1], [NUM2]
STAA [RESULT]

我们也可以在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]

通过我的组合汇编语法,您可以轻松地看到,在字长较短的机器上,高精度操作如何花费成倍的时间。这是64位和128位处理器的真正关键:它们使我们能够在一次操作中处理更多位。某些机器包括使用进位加法运算其他数量的指令(例如,ADC在x86上),但以上示例考虑了任意精度值。


现在,将其扩展到问题,很简单地看到如何添加比可用寄存器大的数字-我们只是将问题分解为寄存器大小的大块,然后从那里开始工作。尽管如@MatteoItalia所述,x87 FPU堆栈具有对80位量的本机支持,但是在缺少该支持的系统中(或完全没有浮点单元的处理器!),必须在软件中执行等效的计算/操作。

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

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

如果有足够的内存,则还可以对任意数量(或“无限” –在实际范围内)精度进行计算,因为需要更高的精度才能使用更多的内存。GNU多精度库中存在此实现的一种实现,它允许对整数,有理数和浮点运算进行无限精度(当然,直到RAM已满)。


2
您没有提到最重要的细节:x86平台上的x87 FPU具有80位宽的浮点寄存器,因此其本机计算实际上是在80位浮点上完成的,无需在软件中进行任何仿真。
Matteo Italia

@MatteoItalia我现在明白了,谢谢。我以为最初的问题是要求对如何处理大于处理器字长的数字执行更通用的概述,而不是x86中扩展的80位浮点数的具体实现(也是为什么我的示例是90位而不是90位) 80 ...)。我现在已经更新了答案以更好地反映这一点,谢谢您的注意。
2014年

5

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

想想乘法。您可能知道乘法表最大为10x10,但是在一张纸上执行123x321可能没有问题:您将其分解为许多小问题,将单个数字相乘,并注意进位等。

处理器可以做同样的事情。在“旧时代”,您有8位处理器可以执行浮点数学运算。但是他们是slooooooow。


1
他们只有在某一点之后才变慢。如果您将自己限制为特定的规范,则可以编写“快速”浮点运算。
拉姆猎犬,2014年

3

“ 32位”实际上是对处理器进行分类的一种方法,而不是一成不变的规则。通常,“ 32位”处理器具有32位通用寄存器。

但是,并没有明确要求处理器中的所有内容都必须以32位完成。例如,“ 32位”计算机具有28位地址总线并不是闻所未闻的,因为制造硬件便宜。出于相同的原因,64位计算机通常仅具有40位或48位内存总线。

浮点运算是大小变化的另一个地方。许多32位处理器支持64位浮点数。他们通过将浮点值存储在比通用寄存器宽的特殊寄存器中来实现。为了将这些大浮点数之一存储在特殊寄存器中,首先将数字分成两个通用寄存器,然后发出指令将它们组合为特殊寄存器中的浮点数。一旦进入这些浮点寄存器,就可以将这些值作为64位浮点运算,而不是作为一对32位半运算。

您提到的80位算术是这种情况的特例。如果您使用的是浮点数,那么您会熟悉浮点取整问题引起的不精确性。舍入的一种解决方案是提高精度,但随后您必须存储更大的数字,并迫使开发人员在内存中使用异常大的浮点值。

英特尔解决方案是浮点寄存器都是80位,但是将值移入/移出这些寄存器的指令主要是使用64位数字。只要您完全在Intel的x87浮点堆栈中操作,所有操作都将以80位精度完成。如果您的代码需要从浮点寄存器中提取这些值之一并将其存储在某个位置,则它将其截断为64位。

故事的寓意:当您深入研究事物时,诸如“ 32位”之类的分类总是比较麻烦!


但是,如果我在16位系统中使用32位浮点值(或在32位系统中使用64位浮点值),则仅需要更多内存(因为它必须两次注册)?还是处理信息会增加开销,所以会花费更多时间吗?
markzzz 2014年

@markzzz:使用多个寄存器几乎总是需要更多时间
Mooing Duck 2014年

将32位浮点值加载到专用寄存器中将花费更多时间。但是,一旦将它们以32位浮点数存储在专用浮点寄存器中,则硬件将以全速对这些浮点值进行操作。请记住,“ 16位”仅指通用寄存器的大小。浮点寄存器的大小专门针对其任务而定,并且可能更宽(在您的情况下为32位宽)
Cort Ammon

2

“ 32位” CPU是其中大多数数据寄存器是32位寄存器,并且大多数指令对这些32位寄存器中的数据进行操作的CPU。一个32位CPU也有可能一次在32位内存之间来回传输数据。大多数寄存器是32位的,并不意味着所有寄存器都是32位的。简短的答案是32位CPU可以具有一些使用其他位数的功能,例如80位浮点寄存器和相应的指令。

正如@spudone在对@ultrasawblade答案的评论中所说的那样,第一个具有集成浮点运算功能的x86 CPU是Intel i486(特别是80486DX,但没有80486SX),根据i486微处理器程序员的第15-1页参考手册的数字寄存器中包括“八个可单独寻址的80位数字寄存器”。i486具有32位内存总线,因此传输80位值将需要3次内存操作。

486代的前身i386没有任何集成的浮点运算。相反,它支持使用外部浮点“协处理器”80387。该协处理器具有与i486集成的功能几乎相同的功能,如《 80387程序员参考手册》的第2-1页所示

80位浮点格式似乎起源于8087和8086和8088的数学协处理器。8086和8088是16位CPU(具有16位和8位内存总线),并且仍然能够通过利用协处理器中的80位寄存器来使用80位浮点格式。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.