我想知道是否有人可以为我提供一些可以利用硬件除法器的浮点平方根算法的示例。
额外细节:我正在开发一个浮点单元,它有一个硬件浮点 IEEE-754 32 位乘法器、加法器和除法器。我已经使用 Newton-Raphson 方法实现了平方根,仅使用乘法和加法/减法,但现在我想比较平方根的吞吐量,如果我有可用的硬件除法器。
1 个难以准确计算的特定输入是 0x7F7FFFFF (3.4028234663852886E38) 的平方根。
我想知道是否有人可以为我提供一些可以利用硬件除法器的浮点平方根算法的示例。
额外细节:我正在开发一个浮点单元,它有一个硬件浮点 IEEE-754 32 位乘法器、加法器和除法器。我已经使用 Newton-Raphson 方法实现了平方根,仅使用乘法和加法/减法,但现在我想比较平方根的吞吐量,如果我有可用的硬件除法器。
1 个难以准确计算的特定输入是 0x7F7FFFFF (3.4028234663852886E38) 的平方根。
@tmyklebu 提供的解决方案显然可以满足您的要求。
r = input value
s(0) = initial estimate of sqrt(r). Example: r with its exponent halved.
s(n) = sqrt(r)
s <- (s + r/s)/2
它具有二次收敛性,执行请求的除法。对于 32 位浮点数,N = 3 或 4 应该这样做。
[编辑 N = 2 为 32 位浮点数,N = 3(可能为 4)为双精度]
[每个 OP 请求编辑] [编辑每个 OP 请求添加的评论]
// Initial estimate
static double S0(double R) {
double OneOverRoot2 = 0.70710678118654752440084436210485;
double Root2 = 1.4142135623730950488016887242097;
int Expo;
// Break R into mantissa and exponent parts.
double Mantissa = frexp(R, &Expo);
int j;
printf("S0 %le %d %le\n", Mantissa, Expo, frexp(sqrt(R), &j));
// If exponent is odd ...
if (Expo & 1) {
// Pretend the mantissa [0.5 ... 1.0) is multiplied by 2 as Expo is odd,
// so it now has the value [1.0 ... 2.0)
// Estimate the sqrt(mantissa) as [1.0 ... sqrt(2))
// IOW: linearly map (0.5 ... 1.0) to (1.0 ... sqrt(2))
Mantissa = (Root2 - 1.0)/(1.0 - 0.5)*(Mantissa - 0.5) + 1.0;
}
else {
// The mantissa is in range [0.5 ... 1.0)
// Estimate the sqrt(mantissa) as [1/sqrt(2) ... 1.0)
// IOW: linearly map (0.5 ... 1.0) to (1/sqrt(2) ... 1.0)
Mantissa = (1.0 - OneOverRoot2)/(1.0 - 0.5)*(Mantissa - 0.5) + OneOverRoot2;
}
// Form initial estimate by using the above mantissa estimate and exponent/2
return ldexp(Mantissa, Expo/2);
}
// S = (S + R/S)/2 method
double Sqrt(double R) {
double S = S0(R);
int i = 5; // May be reduced to 3 or 4 for double and 2 for float
do {
printf("S %u %le %le\n", 5-i, S, (S-sqrt(R))/sqrt(R));
S = (S + R/S)/2;
} while (--i);
return S;
}
void STest(double x) {
printf("T %le %le %le\n", x, Sqrt(x), sqrt(x));
}
int main(void) {
STest(612000000000.0);
return 0;
}
在 3 次迭代后收敛为两倍。
S0 5.566108e-01 40 7.460635e-01
S 0 7.762279e+05 -7.767318e-03
S 1 7.823281e+05 3.040175e-05
S 2 7.823043e+05 4.621193e-
10e+5 S 3 7.02+5 00
S 4 7.823043e+05 0.000000e+00
T 6.120000e+11 7.823043e+05 7.823043e+05