有没有办法用i387 fsqrt指令进行正确的舍入?

R..*_*R.. 8 c floating-point assembly rounding x87

有没有办法用i387 fsqrt指令进行正确的舍入?...

... 除了改变 x87控制字中的精度模式 - 我知道这是可能的,但它不是一个合理的解决方案,因为它有令人讨厌的重入类型问题,如果sqrt操作被中断,精度模式将是错误的.

我正在处理的问题如下:x87 fsqrt操作码在fpu寄存器的精度中执行正确舍入(按IEEE 754)平方根操作,我假设它是扩展(80位)精度.但是,我想用它来实现高效的单精度和双精度平方根函数,并且结果正确舍入(按照当前的舍入模式).由于结果具有过高的精度,因此将结果转换为单精度或双精度的第二步再次舍入,可能会留下不正确舍入的结果.

通过一些操作,可以通过偏差来解决这个问题.例如,我可以通过以2的幂的形式添加偏置来避免过度结果的过度精度,该偏置将双精度值的52个有效位强制为63位扩展精度尾数的最后52位.但我没有看到任何明显的方法用平方根做这样的技巧.

任何聪明的想法?

(还标记为C,因为预期的应用程序是C sqrtsqrtf函数的实现.)

Ste*_*non 14

首先,让我们明白一点:你应该使用SSE而不是x87.SSE sqrtsssqrtsd指令完全符合您的要求,在所有现代x86系统上都受支持,并且速度也快得多.

现在,如果你坚持使用x87,我会从好消息开始:你不需要为浮动做任何事情.您需要2p + 2位来以p位浮点格式计算正确舍入的平方根.因为80 > 2*24 + 2,单精度的额外舍入将始终正确舍入,并且您具有正确的圆角平方根.

现在是坏消息:80 < 2*53 + 2所以双精度没有这样的运气.我可以建议一些解决方法; 这是一个很好的轻松一个我的头顶.

  1. y = round_to_double(x87_square_root(x));
  2. 使用德克尔(头-尾)产物计算a,并b使得y*y = a + b准确.
  3. 计算残差r = x - a - b.
  4. if (r == 0) return y
  5. if (r > 0),让y1 = y + 1 ulp和计算a1,b1y1*y1 = a1 + b1.比较r1 = x - a1 - b1r,并返回任一yy1,这取决于具有较小残差(或一个零低位比特,如果残差大小相等).
  6. if (r < 0),做同样的事情y1 = y - 1 ulp.

此过程仅处理默认的舍入模式; 但是,在定向舍入模式中,简单地舍入到目标格式是正确的.