C:通过大量使用 sin() 来提高函数的性能

标签 c performance math optimization trigonometry

我有一个 C 函数,它根据耗时计算 4 个正弦值。使用 gprof,我发现这个函数使用了 100%(准确地说是 100.7%,哈哈)的 CPU 时间。

void
update_sines(void)
{
    clock_gettime(CLOCK_MONOTONIC, &spec);
    s = spec.tv_sec;
    ms = spec.tv_nsec * 0.0000001;
    etime = concatenate((long)s, ms);

    int k;
    for (k = 0; k < 799; ++k)
    {
        double A1 = 145 * sin((RAND1 * k + etime) * 0.00333) + RAND5;           // Amplitude
        double A2 = 100 * sin((RAND2 * k + etime) * 0.00333) + RAND4;           // Amplitude
        double A3 = 168 * sin((RAND3 * k + etime) * 0.00333) + RAND3;           // Amplitude
        double A4 = 136 * sin((RAND4 * k + etime) * 0.00333) + RAND2;           // Amplitude

        double B1 = 3 + RAND1 + (sin((RAND5 * k) * etime) * 0.00216);           // Period
        double B2 = 3 + RAND2 + (sin((RAND4 * k) * etime) * 0.002);         // Period
        double B3 = 3 + RAND3 + (sin((RAND3 * k) * etime) * 0.00245);           // Period
        double B4 = 3 + RAND4 + (sin((RAND2 * k) * etime) * 0.002);         // Period

        double x = k;                                   // Current x

        double C1 = 0.6 * etime;                            // X axis move
        double C2 = 0.9 * etime;                            // X axis move
        double C3 = 1.2 * etime;                            // X axis move
        double C4 = 0.8 * etime + 200;                          // X axis move

        double D1 = RAND1 + sin(RAND1 * x * 0.00166) * 4;               // Y axis move
        double D2 = RAND2 + sin(RAND2 * x * 0.002) * 4;                 // Y axis move
        double D3 = RAND3 + cos(RAND3 * x * 0.0025) * 4;                // Y axis move
        double D4 = RAND4 + sin(RAND4 * x * 0.002) * 4;                 // Y axis move

        sine1[k] = A1 * sin((B1 * x + C1) * 0.0025) + D1;
        sine2[k] = A2 * sin((B2 * x + C2) * 0.00333) + D2 + 100;
        sine3[k] = A3 * cos((B3 * x + C3) * 0.002) + D3 + 50;
        sine4[k] = A4 * sin((B4 * x + C4) * 0.00333) + D4 + 100;
    }

}

这是 gprof 的输出:

Flat profile:

Each sample counts as 0.01 seconds.
  %   cumulative   self              self     total           
 time   seconds   seconds    calls  Ts/call  Ts/call  name    
100.07      0.04     0.04  

我目前使用它获得大约 30-31 fps 的帧速率。现在我认为有一种更有效的方法可以做到这一点。

如您所见,我已经将所有除法都改为乘法,但这对性能影响很小。

我怎样才能提高这个重数学函数的性能?

最佳答案

除了其他答案中给出的所有其他建议外,这里还有一个纯算法优化。

在大多数情况下,您计算的是 sin(k * a + b) 形式的内容,其中 ab 是常量,k是一个循环变量。如果您还要计算 cos(k * a + b),那么您可以使用 2D rotation matrix形成递归关系(矩阵形式):

|cos(k*a + b)| = |cos(a)  -sin(a)| * |cos((k-1)*a + b)|
|sin(k*a + b)|   |sin(a)   cos(a)|   |sin((k-1)*a + b)|

换句话说,您可以根据上一次迭代的值计算当前迭代的值。因此,您只需要对 k == 0 进行完整的三角计算,但其余部分可以通过此递归计算(一旦您计算了 cos(a)sin(a),它们是常量)。因此,您消除了 75% 的触发函数调用(不清楚是否可以为最后一组触发调用使用相同的技巧)。

关于C:通过大量使用 sin() 来提高函数的性能,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20850291/

相关文章:

java - Lucene 4.x性能问题

math - 如何在 Sage 中进行回归分析?

math - 有限元法介绍引用文献

javascript - 围绕一个点进行 2d 旋转 1000 个随机点

java - 大多数编程语言的时间复杂度?

C: 自定义 strlen() 库函数

c - 下次调用函数后,上次调用的字符串 "remembered"

c - 加载和执行 ELF-64 目标代码——不确定最后的步骤

C++ 守护程序日志功能不写入文件(段错误?)

mysql - 计算引用特定行的行数,MySql 中的多个引用表?