下面的代码演示了atan计算时间的变化:

#include <cstdio>
#include <cstdlib>
#include <cmath>

#include <sys/time.h>
#include <sys/resource.h>
#include <unistd.h>

double get_time()
{
    struct timeval t;
    struct timezone tzp;
    gettimeofday(&t, &tzp);
    return t.tv_sec + t.tv_usec*1e-6;
}

int main() {
    double worst_time = 0.0;
    double best_time = 1e6;

    volatile double x0 = -M_PI/2.0;
    volatile double foo = atan(x0); // SLOW CALL HERE
    volatile double sum = 0.0; // volatile to avoid having tan() call optimized away
    for (double x = x0; x < M_PI/3.0; x += 0.1) {
        volatile double y = x;
        const double start = get_time();
        asm volatile ("":::"memory"); // avoid reordering in -O3
        const double value = atan(y);
        asm volatile ("":::"memory"); // avoid reordering
        const double end = get_time();
        sum += value;

        const double delta = end - start;
        if (delta > worst_time) {
            worst_time = delta;
        }
        if (delta < best_time) {
            best_time = delta;
        }
        printf("* %f (value: %f)\n", delta, y);
    }

    printf("%f / %f\n", worst_time, best_time);

    printf("%f\n", foo);
}

从我的机器上看,最坏的时间是15秒左右,而最好的时间是0秒(太小,无法测量)。
我的机器上的平均时间(此处不显示)大约是1或2 us。
我尝试了不同的编译标志(-O3,静态链接到libm,等等),但是我找不到什么导致最糟糕的时间慢得多。知道吗?
编辑:我正在使用Ubuntu 14.04-gcc 4.8.4
edit2:用atan替换atan2。我不感兴趣的是,atan2是逐段定义的,不同的分支可能需要不同的时间。我有兴趣消除即使调用了atan而不是atan2也可能出现的异常值。
编辑3:
* 0.000015 (value: -1.570796)
* 0.000000 (value: -1.470796)
* 0.000001 (value: -1.370796)
* 0.000001 (value: -1.270796)
* 0.000000 (value: -1.170796)
* 0.000002 (value: -1.070796)
* 0.000000 (value: -0.970796)
* 0.000001 (value: -0.870796)
* 0.000000 (value: -0.770796)
* 0.000000 (value: -0.670796)
* 0.000001 (value: -0.570796)
* 0.000000 (value: -0.470796)
* 0.000003 (value: -0.370796)
* 0.000001 (value: -0.270796)
* 0.000000 (value: -0.170796)
* 0.000000 (value: -0.070796)
* 0.000001 (value: 0.029204)
* 0.000000 (value: 0.129204)
* 0.000002 (value: 0.229204)
* 0.000001 (value: 0.329204)
* 0.000000 (value: 0.429204)
* 0.000001 (value: 0.529204)
* 0.000001 (value: 0.629204)
* 0.000001 (value: 0.729204)
* 0.000001 (value: 0.829204)
* 0.000001 (value: 0.929204)
* 0.000000 (value: 1.029204)
0.000015 / 0.000000 / 0.000001

编辑4:
看来第一个电话就是罪魁祸首!编译器优化了循环外的调用,如果我们强制在循环外计算atanx0,则所有调用都相当快。。。
* 0.000000 (value: -1.570796)
* 0.000001 (value: -1.470796)
* 0.000000 (value: -1.370796)
* 0.000002 (value: -1.270796)
* 0.000001 (value: -1.170796)
* 0.000001 (value: -1.070796)
* 0.000000 (value: -0.970796)
* 0.000000 (value: -0.870796)
* 0.000000 (value: -0.770796)
* 0.000001 (value: -0.670796)
* 0.000000 (value: -0.570796)
* 0.000000 (value: -0.470796)
* 0.000006 (value: -0.370796)
* 0.000001 (value: -0.270796)
* 0.000002 (value: -0.170796)
* 0.000001 (value: -0.070796)
* 0.000000 (value: 0.029204)
* 0.000001 (value: 0.129204)
* 0.000003 (value: 0.229204)
* 0.000000 (value: 0.329204)
* 0.000000 (value: 0.429204)
* 0.000000 (value: 0.529204)
* 0.000001 (value: 0.629204)
* 0.000000 (value: 0.729204)
* 0.000000 (value: 0.829204)
* 0.000000 (value: 0.929204)
* 0.000000 (value: 1.029204)
0.000006 / 0.000000

https://ideone.com/vtUuE6

最佳答案

时间差实际上是由于页面错误(!).
第一次调用该函数时,将访问包含atan2代码的页,并发生页错误。使用mlockall()可以改善这种情况。

关于c - 为什么atan的首次通话比下一个通话慢很多?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/31467813/

10-12 16:12