Floating point x87 FPU指令是确定性的吗?

Floating point x87 FPU指令是确定性的吗?,floating-point,cpu,x87,Floating Point,Cpu,X87,我们正在编写一个仿真器,想知道对于给定的FPU状态,在运行FPU指令(如FDIV)后,FPU的状态是确定性的吗 有许多与英特尔兼容的CPU体系结构实现x87指令集。在测试FPU仿真的正确性时,我们是否应该依赖结果CPU状态 不同的实现是否有不同的循环/计算方式?是的,x87 FPU对基本操作具有确定性+,-,*,/,sqrt。例如,在其默认状态下(全宽有效位和四舍五入到最近的偶数模式),x+y的结果正好是与x和y的数学和的结果最接近的可表示的80位浮点值 兼容芯片制造商对上述操作实施了完全相同的

我们正在编写一个仿真器,想知道对于给定的FPU状态,在运行FPU指令(如FDIV)后,FPU的状态是确定性的吗

有许多与英特尔兼容的CPU体系结构实现x87指令集。在测试FPU仿真的正确性时,我们是否应该依赖结果CPU状态


不同的实现是否有不同的循环/计算方式?

是的,x87 FPU对基本操作具有确定性
+
-
*
/
sqrt
。例如,在其默认状态下(全宽有效位和四舍五入到最近的偶数模式),
x+y
的结果正好是与
x
y
的数学和的结果最接近的可表示的80位浮点值

兼容芯片制造商对上述操作实施了完全相同的定义


在纯CISC传统中,x87的指令集还包含用于计算数学函数的高级指令,例如正弦近似值(
FSIN
)。这些指令的结果因处理器的品牌和型号而异。在仿真器中,您可能只需要提供与仍在使用中一样好的东西。如果您使用宿主语言数学库中的
sinl()
函数的结果,没有人会抱怨,这通常比
FSIN
要好(因为它是通过显式and实现的,而不是调用
FSIN
)。

如果您坚持基本的FPU指令,如果希望FPU算法产生一致的结果,请使用相同的编译器。这还不包括您需要正确初始化FPU库的事实

如果你感兴趣,这里有一些关于这个主题的好读物:


这篇文章中其他文章的链接非常有用。

正如其他人所说,基本的五个操作将在所有x87 FPU上给出相同的结果。然而

x87 FPU是独特的。它的80位寄存器意味着它可能会得到与任何其他FPU不同的结果(例如在PowerPC或具有64位浮点寄存器的ARM上)。这些结果可能更好,也可能更糟。即使将x87舍入模式设置为32位或64位,也不会使其与PowerPC/ARM相同,因为指数保持无界

对于编写仿真器来说,这并不重要,只是这意味着您不必使用主机FPU来模拟x87 FPU。我在这两篇文章中讨论了其中许多问题:


我认为问题在于FPU的模拟,而在编译平台上获得源代码一致结果的建议在很大程度上是不相关的。为什么FSQRT是确定性的,而FSIN不是?@Calmarius,因为+,-,*,/和平方根在IEEE 754中被标准化为必须返回正确四舍五入结果的操作。它们通常被称为五种“基本操作”。实现正确的四舍五入正弦非常困难,因此标准没有强制要求它,所以实现者可以提供一个未正确四舍五入的正弦函数,或者根本没有正弦函数,并且仍然称他们的实现符合IEEE 754。@Calmarius:对于任何特定大小的输入和输出,这都是可能的(而且并不困难)构造一个sqrt(x)函数,该函数将知道其报告结果是否高于、低于或等于数值上的完美值。如果计算的结果比预期结果长一位,则该额外位加上正确值是否高于或低于表示值的知识将足以使用任何期望的舍入模式计算结果。对于sin(x),这样的确定通常是不可能的。几乎任何想要从sin(x)获得准确性的代码都需要在最后一次计算产生x值之前执行参数缩减。例如,如果想要在x接近3141592654时计算(x/1.0E9)的正弦,首先需要计算x和(1E9*pi)之间的差值,然后将其除以1E9。如果没有先进行参数化简,就将x除以1E9,则产生的舍入误差将使任何未来参数化简的准确性变得无关紧要。