通过您的方法,每次迭代都会使正确位数加倍。
使用表格获取初始的4位(例如),第一次迭代后您将拥有8位,第二次迭代后将拥有16位,在第四次迭代后您将拥有所有所需的位数(由于double存储52+1位尾数)。
对于表格查找,您可以从输入中提取[0.5,1[中的尾数和指数(使用类似frexp的函数),然后通过乘以适当的2的幂来将尾数归一化到[64,256[中。
mantissa *= 2^K
exponent -= K
接下来,你的输入数字仍为 mantissa*2^exponent
。K 必须是 7 或 8,以获得偶数指数。您可以从包含所有小数部分平方根的表中获取迭代的初始值。执行 4 次迭代以获取 mantissa 的平方根 r。结果为 r*2^(exponent/2)
,使用类似于 ldexp
的函数构造。
编辑。我在下面放了一些 C++ 代码来说明这一点。改进测试的 OP 函数 sr1 计算 2^24 的平方根需要 2.78 秒;我的函数 sr2 需要 1.42 秒,硬件 sqrt 需要 0.12 秒。
#include <math.h>
#include <stdio.h>
double sr1(double x)
{
double last = 0;
double r = x * 0.5;
int maxIters = 100;
for (int i = 0; i < maxIters; i++) {
r = (r + x / r) / 2;
if ( fabs(r - last) < 1.0e-10 )
break;
last = r;
}
return r;
}
double sr2(double x)
{
static const int ROOTS256[] = {
0,1,1,2,2,2,2,3,3,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,6,6,6,6,6,6,6,6,6,6,6,6,
7,7,7,7,7,7,7,7,7,7,7,7,7,7,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,9,9,9,9,9,9,9,9,9,9,9,9,9,
9,9,9,9,9,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,11,11,11,11,11,
11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,12,12,12,12,12,12,12,12,12,12,12,12,
12,12,12,12,12,12,12,12,12,12,12,12,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,
13,13,13,13,13,13,13,13,13,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,
14,14,14,14,14,14,14,14,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
15,15,15,15,15,15,15,15,15,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16 };
int exponent;
double mantissa = frexp(x,&exponent);
if (mantissa == 0) return 0;
if (exponent & 1) { mantissa *= 128; exponent -= 7; }
else { mantissa *= 256; exponent -= 8; }
double root = ROOTS256[(int)floor(mantissa)];
for (int it=0;it<4;it++)
{
root = 0.5 * (root + mantissa / root);
}
return ldexp(root,exponent>>1);
}
int main()
{
double s = 0;
int mx = 1<<24;
for (int i=0;i<mx;i++) s += sr2(i);
}