简体   繁体   English

为什么std :: sin()和std :: cos()比sin()和cos()慢?

[英]Why is std::sin() and std::cos() slower than sin() and cos()?

Test code: 测试代码:

#include <cmath>
#include <cstdio>

const int N = 4096;
const float PI = 3.1415926535897932384626;

float cosine[N][N];
float sine[N][N];

int main() {
    printf("a\n");
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < N; j++) {
            cosine[i][j] = cos(i*j*2*PI/N);
            sine[i][j] = sin(-i*j*2*PI/N);
        }
    }
    printf("b\n");
}

Here is the time: 这是时间:

$ g++ main.cc -o main
$ time ./main
a
b

real    0m1.406s
user    0m1.370s
sys     0m0.030s

After adding using namespace std; 添加using namespace std; , the time is: , 现在的时间是:

$ g++ main.cc -o main
$ time ./main
a
b

real    0m8.743s
user    0m8.680s
sys     0m0.030s

Compiler: 编译:

$ g++ --version
g++ (Ubuntu/Linaro 4.5.2-8ubuntu4) 4.5.2

Assembly: 部件:

Dump of assembler code for function sin@plt:                                    
0x0000000000400500 <+0>:     jmpq   *0x200b12(%rip)        # 0x601018 <_GLOBAL_OFFSET_TABLE_+48>
0x0000000000400506 <+6>:     pushq  $0x3                                     
0x000000000040050b <+11>:    jmpq   0x4004c0                                 
End of assembler dump.

Dump of assembler code for function std::sin(float):                            
0x0000000000400702 <+0>:     push   %rbp                                     
0x0000000000400703 <+1>:     mov    %rsp,%rbp                                
0x0000000000400706 <+4>:     sub    $0x10,%rsp                               
0x000000000040070a <+8>:     movss  %xmm0,-0x4(%rbp)                         
0x000000000040070f <+13>:    movss  -0x4(%rbp),%xmm0                         
0x0000000000400714 <+18>:    callq  0x400500 <sinf@plt>                      
0x0000000000400719 <+23>:    leaveq                                          
0x000000000040071a <+24>:    retq                                            
End of assembler dump.

Dump of assembler code for function sinf@plt:                                   
0x0000000000400500 <+0>:     jmpq   *0x200b12(%rip)        # 0x601018 <_GLOBAL_OFFSET_TABLE_+48>
0x0000000000400506 <+6>:     pushq  $0x3                                     
0x000000000040050b <+11>:    jmpq   0x4004c0                                 
End of assembler dump.

You're using a different overload: 你正在使用不同的重载:

Try 尝试

        double angle = i*j*2*PI/N;
        cosine[i][j] = cos(angle);
        sine[i][j] = sin(angle);

it should perform the same with or without using namespace std; 无论是否using namespace std;它都应该执行相同的操作using namespace std;

I guess the difference is that there are overloads for std::sin() for float and for double, while sin() only takes double. 不同之处在于,对于float和double,std :: sin()存在重载,而sin()只需要加倍。 Inside std::sin() for floats, there may be a conversion to double, then a call to std::sin() for doubles, and then a conversion of the result back to float, making it slower. 在浮点数的std :: sin()里面,可能有一个转换为double,然后调用std :: sin()为double,然后将结果转换回float,使其变慢。

Use -S flag in compiler command line and check the difference between assembler output. 在编译器命令行中使用-S标志并检查汇编器输出之间的差异。 Maybe using namespace std; 也许using namespace std; gives a lot of unused stuff in executable file. 在可执行文件中提供了大量未使用的东西。

I did some measurements using clang with -O3 optimization, running on an Intel Core i7 . 我使用clang -O3优化进行了一些测量,在Intel Core i7上运行。 I found that: 我找到:

  • std::sin on float has the same cost as sinf float std::sinsinf具有相同的成本
  • std::sin on double has the same cost as sin std::sin on doublesin成本相同
  • The sin functions on double are 2.5x slower than on float (again, running on an Intel Core i7 ). double的sin函数比float慢2.5倍(再次,在Intel Core i7上运行)。

Here is the full code to reproduce it: 以下是重现它的完整代码:

#include <chrono>
#include <cmath>
#include <iostream>

template<typename Clock>
struct Timer
{
    using rep = typename Clock::rep;
    using time_point = typename Clock::time_point;
    using resolution = typename Clock::duration;

    Timer(rep& duration) :
    duration(&duration) {
        startTime = Clock::now();
    }
    ~Timer() {
        using namespace std::chrono;
        *duration = duration_cast<resolution>(Clock::now() - startTime).count();
    }
private:

    time_point startTime;
    rep* duration;
};

template<typename T, typename F>
void testSin(F sin_func) {
  using namespace std;
  using namespace std::chrono;
  high_resolution_clock::rep duration = 0;
  T sum {};
  {
    Timer<high_resolution_clock> t(duration);
    for(int i=0; i<100000000; ++i) {
      sum += sin_func(static_cast<T>(i));
    }
  }
  cout << duration << endl;
  cout << "  " << sum << endl;
}

int main() {
  testSin<float> ([] (float  v) { return std::sin(v); });
  testSin<float> ([] (float  v) { return sinf(v); });
  testSin<double>([] (double v) { return std::sin(v); });
  testSin<double>([] (double v) { return sin(v); });
  return 0;
}

I'd be interested if people could report, in the comments on the results on their architectures, especially regarding float vs. double time. 如果人们可以在关于他们的架构的结果的评论中报告,特别是关于floatdouble时间,我会感兴趣。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM