糟糕的浮点魔法

时间:2011-10-21 11:04:51

标签: qt floating-point

我有一个奇怪的浮点问题。

背景

我正在为一个带有大整数算术协处理器的8位处理器实现一个双精度(64位)IEEE 754浮点库。为了测试这个库,我将我的代码返回的值与Intel的浮点指令返回的值进行比较。这些并不总是一致,因为英特尔的浮点单元在内部以80位格式存储值,带有64位尾数。

示例(全部以十六进制):

X = 4C816EFD0D3EC47E:
  偏差指数= 4C8(真指数= 1C9),尾数= 116EFD0D3EC47E

Y = 449F20CDC8A5D665:
  偏差指数= 449(真指数= 14A),尾数= 1F20CDC8A5D665

计算X * Y

尾数的乘积为10F5643E3730A17FF62E39D6CDB0,当舍入到53(十进制)位时为10F5643E3730A1(因为7FF62E39D6CDB0的最高位为零)。所以结果中的正确尾数是10F5643E3730A1。

但如果使用64位尾数执行计算,则10F5643E3730A17FF62E39D6CDB0向上舍入为10F5643E3730A1800,再次舍入为53位时变为10F5643E3730A2。最低有效数字已从1更改为2.

总结一下:我的库返回正确的尾数10F5643E3730A1,但英特尔硬件返回(正确)10F5643E3730A2,因为它的内部64位尾数。

问题:

现在,这是我不明白的事情:有时英特尔硬件在尾数中返回10F5643E3730A1!我有两个程序,一个Windows控制台程序和一个Windows GUI程序,都是由Qt使用g ++ 4.5.2构建的。控制台程序按预期返回10F5643E3730A2,但GUI程序返回10F5643E3730A1。他们正在使用相同的库函数,它有三个指令:

fldl   -0x18(%ebp)
fmull  -0x10(%ebp)
fstpl  0x4(%esp)

这三个指令在两个程序中计算出不同的结果。 (我已经在调试器中逐步完成了它们。)在我看来,这可能是Qt在其GUI启动代码中配置FPU所做的事情,但我找不到任何关于此的文档。有没有人知道这里发生了什么?

2 个答案:

答案 0 :(得分:5)

函数的指令流和输入不能唯一地确定其执行。您还必须考虑执行时处理器中已经建立的环境。

如果检查x87控制字,您会发现它设置为两种不同的状态,对应于您观察到的两种行为。在一个中,精度控制[位9:8]已设置为10b(53位)。另一方面,它被设置为11b(64位)。

至于什么正在建立非默认状态,它可能是在执行代码之前在该线程中发生的任何事情。任何被拉入的图书馆都可能是嫌疑人。如果你想做一些考古学,吸烟枪通常是fldcw指令(虽然控制字也可以由fldenvfrstorfinit写入。

答案 1 :(得分:3)

通常它是一个编译器设置。检查以下Visual C ++页面: http://msdn.microsoft.com/en-us/library/aa289157%28v=vs.71%29.aspx

或此文件的英特尔: http://cache-www.intel.com/cd/00/00/34/76/347605_347605.pdf

特别是intel文档提到处理器内部的一些标志,用于确定FPU指令的行为。这解释了为什么相同的代码在2个程序中表现不同(一个设置标志与另一个不同)。