只是对GCC上math.h的标准sqrt()感到好奇,我用Newton-Raphson编写了自己的sqrt()!
sqrt()
pgvzfuti1#
是的,我知道fsqrt。但是CPU是怎么做的?我不能调试硬件现代CPU中的典型div/sqrt硬件使用2的幂基数一次计算多个结果位。例如http://www.imm.dtu.dk/~alna/pubs/ARITH20.pdf提供了一个Radix-16 div/sqrt ALU的设计细节,并将其与Penryn中的设计进行了比较。(他们声称更低的延迟和更少的功率。)我看了看图片;看起来一般的想法是做一些事情,并通过乘法器和加法器迭代地反馈结果,基本上就像长除法一样。我认为类似于你在软件中做一次一位除法的方式。Intel Broadwell引入了Radix-1024 div/sqrt单元。This discussion on RWT询问Penryn(Radix-16)和Broadwell之间的变化。例如,加宽SIMD向量除法器,使256位除法比128位除法慢,以及增加基数。也许还能看到
div
RCPSS
但无论硬件如何工作,IEEE要求sqrt(和穆尔/div/add/sub)来给予一个 * 正确舍入的 * 结果,即error <= 0.5 ulp,所以你不需要知道它是如何工作的,只需要知道性能。这些操作是特殊的,其他函数如log和sin没有 * 这个要求,而真实的库实现通常并不那么准确(对于接近Pi/2的输入,x87 fsin is definitely not that accurate,其中范围缩减中的灾难性取消会导致潜在的 * 巨大 * 相对误差)。有关x86指令表,包括标量和SIMD sqrtsd/sqrtss及其更广泛版本的吞吐量和延迟,请参见https://agner.org/optimize/。对于非x86硬件sqrt,你必须查看其他供应商发布的数据,或者测试人员的测试结果。与大多数指令不同,sqrt的性能通常依赖于数据(通常更高的有效位或更大的结果需要更长的时间)。
sqrt
log
sin
fsin
sqrtsd
sqrtss
gorkyyrv2#
sqrt是由C定义的,所以很可能你必须在glibc中查找。您没有指定您要求的架构,所以我认为假设x86-64是安全的。如果是这种情况,它们定义在:
glibc
tl;dr它们可以通过调用x86-64平方根指令sqrts{sd}:
sqrts{sd}
此外,为了便于讨论,如果你启用了快速数学(如果你关心结果精度,你可能不应该做),你会看到大多数编译器实际上会内联调用并直接发出sqrts{sd}指令:https://godbolt.org/z/Wb4unC
2条答案
按热度按时间pgvzfuti1#
是的,我知道fsqrt。但是CPU是怎么做的?我不能调试硬件
现代CPU中的典型div/sqrt硬件使用2的幂基数一次计算多个结果位。例如http://www.imm.dtu.dk/~alna/pubs/ARITH20.pdf提供了一个Radix-16 div/sqrt ALU的设计细节,并将其与Penryn中的设计进行了比较。(他们声称更低的延迟和更少的功率。)我看了看图片;看起来一般的想法是做一些事情,并通过乘法器和加法器迭代地反馈结果,基本上就像长除法一样。我认为类似于你在软件中做一次一位除法的方式。
Intel Broadwell引入了Radix-1024 div/sqrt单元。This discussion on RWT询问Penryn(Radix-16)和Broadwell之间的变化。例如,加宽SIMD向量除法器,使256位除法比128位除法慢,以及增加基数。
也许还能看到
div
如何左对齐位进行了一些猜测,并使用与RCPSS
相同的硬件来获得初始猜测,等等。但无论硬件如何工作,IEEE要求
sqrt
(和穆尔/div/add/sub)来给予一个 * 正确舍入的 * 结果,即error <= 0.5 ulp,所以你不需要知道它是如何工作的,只需要知道性能。这些操作是特殊的,其他函数如log
和sin
没有 * 这个要求,而真实的库实现通常并不那么准确(对于接近Pi/2的输入,x87fsin
is definitely not that accurate,其中范围缩减中的灾难性取消会导致潜在的 * 巨大 * 相对误差)。有关x86指令表,包括标量和SIMD
sqrtsd
/sqrtss
及其更广泛版本的吞吐量和延迟,请参见https://agner.org/optimize/。对于非x86硬件sqrt,你必须查看其他供应商发布的数据,或者测试人员的测试结果。
与大多数指令不同,
sqrt
的性能通常依赖于数据(通常更高的有效位或更大的结果需要更长的时间)。gorkyyrv2#
sqrt
是由C定义的,所以很可能你必须在glibc
中查找。您没有指定您要求的架构,所以我认为假设x86-64是安全的。如果是这种情况,它们定义在:
tl;dr它们可以通过调用x86-64平方根指令
sqrts{sd}
:此外,为了便于讨论,如果你启用了快速数学(如果你关心结果精度,你可能不应该做),你会看到大多数编译器实际上会内联调用并直接发出
sqrts{sd}
指令:https://godbolt.org/z/Wb4unC