小编典典

确定浮点平方根

algorithm

如何确定浮点数的平方根?牛顿-拉夫森法是个好方法吗?我也没有硬件平方根。我也没有硬件除法(但是我已经实现了浮点除法)。

如果可能的话,我宁愿尽量减少分割的数量,因为它们是如此昂贵。

另外,减少迭代总数的初始猜测应该是什么?

非常感谢!


阅读 356

收藏
2020-07-28

共1个答案

小编典典

当您使用Newton-Raphson计算平方根时,您实际上想使用迭代来找到倒数平方根(此后,您可以简单地乘以输入值(并舍入四舍五入)以产生平方根)。

更准确地说:我们使用函数f(x) = x^-2 - n。显然,如果f(x) = 0,则x = 1/sqrt(n)。这引起了牛顿迭代:

x_(i+1) = x_i - f(x_i)/f'(x_i)
        = x_i - (x_i^-2 - n)/(-2x_i^-3)
        = x_i + (x_i - nx_i^3)/2
        = x_i*(3/2 - 1/2 nx_i^2)

注意(与平方根的迭代不同),平方根的倒数不涉及除法运算,因此通常效率更高。

我在关于鸿沟的问题中提到,您应该查看现有的软浮动库,而不是重新发明轮子。该建议也适用于此。此功能已在现有的软浮点库中实现。


编辑:提问似乎依然混淆,让我们工作的例子:sqrt(612)6121.1953125 x 2^9(或b1.0011001 x 2^9,如果您更喜欢二进制)。拉出指数(9)的偶数部分,将输入写为f * 2^(2m),其中m是整数,f并且在[1,4)范围内。然后我们将有:

sqrt(n) = sqrt(f * 2^2m) = sqrt(f)*2^m

将这个减少应用于我们的例子给出f = 1.1953125 * 2 = 2.390625b10.011001)和m = 4。现在进行牛顿-
拉普森迭代x = 1/sqrt(f),使用0.5的初始猜测值进行查找(正如我在评论中指出的那样,该猜测值收敛于所有f,但是使用线性近似作为初始猜测值可以做得更好):

x_0 = 0.5
x_1 = x_0*(3/2 - 1/2 * 2.390625 * x_0^2)
    = 0.6005859...
x_2 = x_1*(3/2 - 1/2 * 2.390625 * x_1^2)
    = 0.6419342...
x_3 = 0.6467077...
x_4 = 0.6467616...

因此,即使有了(相对较差的)初始猜测,我们也可以快速收敛到的真实值1/sqrt(f) = 0.6467616600226026

现在我们简单地组装最终结果:

sqrt(f) = x_n * f = 1.5461646...
sqrt(n) = sqrt(f) * 2^m = 24.738633...

并检查:sqrt(612)= 24.738633 …

显然,如果要正确舍入,则需要仔细分析以确保在计算的每个阶段都具有足够的精度。这需要仔细的簿记,但这不是火箭科学。您只需保持谨慎的错误界限,并通过算法传播它们。

如果要纠正舍入而不显式检查残差,则需要将sqrt(f)计算为2p +
2位的精度(其中p是源和目标类型的精度)。但是,您也可以采用将sqrt(f)计算为p位多一点的策略,对该值取平方,并在必要时将尾随位调整一位(这通常更便宜)。

sqrt很不错,因为它是一元函数,这使得在商品硬件上对单精度进行详尽的测试成为可能。

您可以sqrtf在opensource.apple.com上找到OS
X软浮点函数,该函数使用上述算法(我写了它,发生了)。它是根据APSL许可的,可能适合或不适合您的需求。

2020-07-28