当您使用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)。
612是
1.1953125 x 2^9(或
b1.0011001 x2^9,如果您更喜欢二进制)。拉出指数(9)的偶数部分,将输入写为
f * 2^(2m),其中
m是整数,
f并且在[1,4)范围内。然后我们将有:
sqrt(n) = sqrt(f * 2^2m) = sqrt(f)*2^m
将这个减少应用于我们的例子给出
f = 1.1953125 * 2 = 2.390625(
b10.011001)和
m = 4。现在进行牛顿-
拉普森迭代
x =1/sqrt(f),使用0.5的初始猜测值进行查找(正如我在评论中指出的那样,该猜测值收敛于所有
f,但是使用线性近似作为初始猜测值可以做得更好):
x_0 = 0.5x_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许可的,可能适合或不适合您的需求。



