5

我正在实时渲染 500x500 点。我必须使用 atan() 和 sin() 函数计算点的位置。通过使用 atan() 和 sin() 我得到24 fps(每秒帧数)。

float thetaC = atan(value);
float h = (value) / (sin(thetaC)));

如果我不使用 sin() 我得到52 fps

如果我不使用 atan() 我是30 fps

所以,最大的问题是 sin()。如何使用 Fast Sin 版本。我可以为此创建一个查找表吗?我没有任何特定的值来创建 LUT。在这种情况下我该怎么办?

PS:我也尝试过 ASM 的快速 sin 功能,但没有任何区别。

谢谢。

4

3 回答 3

11

稍等一下....

你有一个三角形,你正在计算斜边。首先,您要atan(value)获取角度,然后value再次使用 withsin来计算h。所以我们有三角形的一侧是1的场景:

   /|
h / | value
 /  |
/C__|
  1

您真正需要做的就是计算h = sqrt(value*value + 1);……但是,sqrt这也不是最快的功能。

也许我错过了重点,或者你遗漏了一些东西。我一直使用查找表sincos,并发现它们很快。如果您不提前知道这些值,那么您需要进行近似,但这意味着乘法、截断为整数(可能还有符号转换)以获得数组索引。如果您可以将单位转换为整数(有效地将浮点数转换为定点),则查找速度会更快。

于 2012-10-24T02:50:34.997 回答
6

这取决于您需要的准确性。sin 的最大导数是 1,因此如果 x1 和 x2 在彼此的 epsilon 范围内,则 sin(x1) 和 sin(x2) 也在 epsilon 范围内。如果您只需要精度在 0.001 以内,那么您可以创建一个 1000 * PI = 3142 点的查找表,然后查找最接近您需要的值。这可能比本机代码更快,因为本机代码(可能)使用查找表来查找多项式系数,然后进行插值,并且该表可以足够小以便轻松地保留在缓存中。

如果您需要在整个范围内完全准确,那么您可能没有比这更好的方法了。

如果您愿意,您还可以在 (1/sin(x)) 上创建一个查找表,因为这是您实际感兴趣的函数。无论哪种方式,您都需要小心 sin(x) = 0,因为 sin(x) 中的一个小错误可能会导致 1/sin(x) 中的一个大错误。定义你的容错对于弄清楚你可以走什么捷径很重要。

您将使用以下内容创建查找表:

float *table = malloc(1000 * sizeof(float));
for(int i = 0; i < 1000; i++){
  table[i] = sin(i/1000.0);
}

并会像这样访问它

float fastSin(float x){
  int index = x * 1000.0;
  return table[index];
}

此代码不完整(由于数组边界,0 < x < 1 之外的任何内容都会崩溃),但应该可以帮助您入门。

于 2012-10-24T02:26:13.583 回答
2

对于 sin(但不是 atan),您实际上可以比表格更简单——只需创建

float sin_arr[31416]; //Or as much precision as you need
for (int i=0; i<31416; ++i)
   sin_arr[i] = sin( i / 10000.0 );

//...

float h = (value) / sin_arr[ (int)(thetaC*10000.0) % 31416 ];

我的猜测是,这会给你带来速度上的提升。

于 2012-10-24T02:36:00.260 回答