我正在尝试使用非恢复算法来计算浮点数的平方根。
例如,说x = 1001
,平方根为31.6386
我想使用非恢复方法计算此平方根 。
我尝试按照论文中的方法进行操作:
Implementation of Single Precision Floating Point Square Root on FPGAs
但似乎我的结果略微偏离了1位。我虽然无法弄清楚原因。
例如,我在下面编写的程序将产生以下结果:
correct_result =
41FD1BD2
myresult =
41FD1BD1
error =
1.192093e-007
C++ version of the code
:
#include <iostream>
#include <cmath>
using namespace std;
union newfloat{
float f;
int i;
};
int main () {
// Input number
newfloat x;
cout << "Enter Number: ";
cin >> x.f;
// Pull out exponent and mantissa
int exponent = (x.i >> 23) & 0xFF;
int mantissa = (x.i & 0x7FFFFF) | ((exponent && exponent) << 23);
// Calculate new exponent
int new_exponent = (exponent >> 1) + 63 + (exponent & 1);
// Shift right (paper says shift left but shift left doesn't work?)
if (exponent & 1) {
mantissa = mantissa >> 1;
cout << " Shifted right " << endl;
}
// Create an array with the bits of the mantissa
unsigned int D [48];
for (int i = 47; i >= 0; i--) {
if (i >= 24) {
D[i] = (mantissa >> (i-24)) & 1;
} else {
D[i] = 0;
}
}
// == Perform square root ==
// Set q24 = 0, r24 = 0 and then iterate from k = 23 to 0
int q[25] = {0}; // 25 element array, indexing ends at 24
int r[25] = {0};
for (int k = 23; k >= 0; k--) {
if (r[k+1] >= 0) {
r[k] = ((r[k+1] << 2) | (D[2*k+1] << 1) | D[2*k] ) - (q[k+1] << 2 | 1 );
} else {
r[k] = ((r[k+1] << 2) | (D[2*k+1] << 1) | D[2*k] ) + (q[k+1] << 2 | 0x3 );
}
if (r[k] >= 0) {
q[k] = (q[k+1] << 1) | 1;
} else {
q[k] = q[k+1] << 1;
}
if (k == 0) {
if (r[0] < 0) {
r[0] = r[0] + (q[0] << 1) | 1;
}
}
}
// Create quotient from LSBs of q[]
int Q = 0;
for (int i = 0; i <= 23; i++) {
Q = Q | ((q[i] & 1) << i);
}
// Option 1 Rounding
//if (r[0] > 0) // Works for 10, 1001, 1021, but not 1012
// Q = Q + 1;
// Option 2 Rounding (No rounding)
// Works for 1012, Doesn't work for 10, 1001, 1021
// Option 3 Rounding (Calculate the next 3 Quotient bits to get a guard round and sticky bit)
// Calculate correct result:
newfloat correct_result;
correct_result.f = sqrt(x.f);
// Form my result into a single number
newfloat myresult;
myresult.i = (new_exponent << 23) | (Q & 0x7FFFFF);
// Print results
cout << hex << "My result: " << myresult.i << endl;
cout << hex << "Correct: " << correct_result.i << endl;
return 0;
}
答案 0 :(得分:1)
首先让我强调一下文章中的相关部分:
您需要再看一下如何完成加法/减法。您的代码是以常规双数字执行的,但我认为该算法在设计时考虑了整数modular arithmetic。
因此,如果您查看本文后面列出的示例,0011 - 0101
的计算将包围1110
。
这可以解释为什么你得到了错误的结果,我认为:)
答案 1 :(得分:1)
我正在查看程序的c ++版本,并在今天阅读该文档。在我看来,该算法旨在提供商和余数。如在提供的示例中,他使用他的算法得到127的平方根,它提供了11 + R 6的结果.11 2 + 6 = 127.
这是一个整数,但每种数据类型都有其精度限制。这让我相信你的程序正在按预期执行,它只是你已经精度不足,至少对于计算平方根的方式,以及正在使用的数据类型。我希望你能在r [0]中找到你的精确“丢失”精度。
我从你想要的代码中的注释中看到,或者试图计算出额外的精度。这似乎是一条合理的尝试之路。请注意,除了执行此操作所需的其他更改之外,您还必须取出(或移动)支票k == 0;因为它会修改余数,这会弄乱循环。
我认为真正的问题是您可以接受的尺寸精度。例如,c ++ sqrt函数(和你的)在sqrt(2)上偏差为0.00000002。似乎没有人介意。考虑到你编写的程序是从c ++ sqrt函数中删除的,而不是在它不匹配的实例中。我花了大部分时间将其分解,测试各个部分,并审查主题,并且找不到任何明显错误的内容。对我来说,政府工作似乎足够接近。