x87 FPU指令是确定性的吗?

3

我们正在编写一个模拟器,并想知道在给定FPU状态下,运行FPU指令(例如FDIV)后,FPU的状态是否是确定性的?

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

不同的实现会进行不同的舍入/计算吗?

3个回答

5
是的,对于基本操作+-*/sqrt,x87 FPU是确定性的。例如,在其默认状态下(全宽度有效数字和四舍五入到最近偶数模式),x + y的结果恰好是最接近xy的数学求和结果的可表示80位浮点值。
兼容芯片制造商已实现上述操作的完全相同定义。
在纯CISC传统中,x87指令集还包含高级指令来计算数学函数,例如正弦的近似值(FSIN)。这些指令的结果因处理器品牌和型号而异。在您的仿真器中,您可能只需要提供使用中最差的实现之一即可。如果您使用主机语言的数学库中的sinl()函数的结果(通常比FSIN更好,因为它是通过显式参数减少多项式逼近实现的,而不是调用FSIN),则没有人会抱怨。

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

2
如果您坚持使用基本的FPU指令,并对FPU算法使用相同的编译器,那么应该是一致的。这还不包括您需要正确初始化FPU库的事实。
如果您有兴趣,下面是一些相关的好文章链接:https://randomascii.wordpress.com/2013/07/16/floating-point-determinism。这篇文章中其他文章的链接非常有用。

1
我认为这个问题与 FPU 的模拟有关,而为了获得跨编译平台的源代码一致结果的建议在很大程度上是不相关的。 - Pascal Cuoq

1

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

x87 FPU很特别。它的80位寄存器意味着它可能会得到与任何其他FPU(比如具有64位浮点寄存器的PowerPC或ARM)不同的结果。这些结果可能更好或更差。即使将x87舍入模式设置为32位或64位,也不能使其与PowerPC/ARM相同,因为指数仍未受限制。

对于编写仿真器来说,这并不重要,除了这意味着您不能一定使用主机FPU来模拟x87 FPU。我在这两篇文章中涵盖了许多这些问题:

http://randomascii.wordpress.com/2013/07/16/floating-point-determinism http://randomascii.wordpress.com/2012/03/21/intermediate-floating-point-precision/


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接