GCC的sqrt()如何在编译后工作?使用哪种root方法?牛顿迭代?

Res*_*ily 5 c math assembly function sqrt

sqrt()关于GCC的math.h 标准的好奇心.我sqrt()使用Newton-Raphson 编写了自己的代码!

Pet*_*des 16

是的,我知道fsqrt.但CPU是如何做到的呢?我无法调试硬件

现代CPU中的典型div/sqrt硬件使用2基数的幂来一次计算多个结果位.例如http://www.imm.dtu.dk/~alna/pubs/ARITH20.pdf提供了Radix-16 div/sqrt ALU的设计细节,并将其与Penryn中的设计进行了比较.(他们声称延迟更低,功耗更低.)我看了看图片; 看起来一般的想法是做一些事情,并通过乘法器和加法器反复提供结果,基本上就像长除法.而且我认为类似于你如何在软件中进行按位划分.

英特尔Broadwell推出了Radix-1024 div/sqrt单元. 关于RWT的讨论询问了Penryn(Radix-16)和Broadwell之间的变化.例如,加宽SIMD向量分频器,使得256位除法与128位相比较慢,并且增加基数.

也许也看到了


但是,无论硬件如何工作,IEEE都要求sqrt(和mul/div/add/sub)给出正确的舍入结果,即错误<= 0.5 ulp,因此您不需要知道它是如何工作的,只需要知道性能.这些操作是特殊的,其他的功能,如logsin没有这个要求,而真正的库实现通常是不准确的.(对于Pi/2附近的输入,x87 fsin绝对不是那么准确,在范围减少中的灾难性消除会导致潜在的巨大相对误差.)

有关x86指令表,请参阅https://agner.org/optimize/,包括标量和SIMD sqrtsd/ sqrtss及其更广泛版本的吞吐量和延迟.我收集了浮点除法与浮点乘法的结果

对于非x86硬件sqrt,您必须查看其他供应商发布的数据,或者测试过它的人的结果.

与大多数指令不同,sqrt性能通常与数据有关.(通常更高有效位或更大幅度的结果需要更长时间).


CAF*_*FxX 4

sqrt由 C 定义,因此很可能您必须查看glibc.

您没有指定您要求的架构,所以我认为假设 x86-64 是安全的。如果是这种情况,它们的定义如下:

tl;dr 它们只是通过调用 x86-64 平方根指令来实现sqrts{sd}

此外,为了讨论的目的,如果您启用快速数学(如果您关心结果精度,您可能不应该这样做),您将看到大多数编译器实际上会内联调用并直接发出指令sqrts{sd}

https://godbolt.org/z/Wb4unC

  • 只要您使用“-fno-math-errno”,编译器就可以完全内联“sqrt”。否则,GCC 内联它加上一个比较和分支来调用 NaN 输入的库版本,因为早期 C 标准留下了一个愚蠢的要求,即数学函数在 FP 错误(例如 sqrt 的负输入)上设置“errno”。(基本上是关于 FP 无效异常)。 (6认同)
  • 使用完整的“-ffast-math”,编译器有时会使用“rsqrtps”+牛顿迭代将 sqrt(x) 近似为“x * approx_recip_sqrt(x)”,尽管这需要对非零“x”进行修复。在现代 x86 上不值得这样做,尤其是对于标量。也许对于矢量来说,如果它是你在循环中做的唯一事情,否则仍然不是。 (4认同)