std :: complex multiplication非常慢

时间:2017-03-07 22:37:01

标签: gcc c++-standard-library

我注意到,使用重载std::complex运算符而不是写出操作,乘以两个*值会慢得多。我看到了50倍的差异。这完全是荒谬的。我知道运算符需要在输入中检查NaN,因为定义了无穷大的复杂程度。这真的能说明50倍的时差吗?

我使用带有标志-O3 -mavx -mavx2 -msse2 -mfma -mbmi的GCC 5.4.0。

这是测试代码:

#include <iostream>
#include <complex>
#include <chrono>
#include <vector>

int main( void ) {
  size_t N = 10000;
  std::vector< std::complex< double >> inbuf( N );
  for( size_t k = 0; k < N; ++k ) {
     inbuf[ k ] = std::complex< double >( std::rand(), std::rand() ) / ( double )RAND_MAX - 0.5;
  }

  std::complex< double > c2 = { 0, 0 };
  auto t0 = std::chrono::steady_clock::now();
  for( size_t i = 0; i < 10000; ++i ) {
     for( size_t j = 0; j < N - 1; ++j ) {
        double re = inbuf[ j ].real() * inbuf[ j + 1 ].real() - inbuf[ j ].imag() * inbuf[ j + 1 ].imag();
        double im = inbuf[ j ].real() * inbuf[ j + 1 ].imag() + inbuf[ j ].imag() * inbuf[ j + 1 ].real();
        c2.real( c2.real() + re );
        c2.imag( c2.imag() + im );
     }
  }
  auto t1 = std::chrono::steady_clock::now();
  double time = ( std::chrono::duration< float >( t1 - t0 ) ).count();
  std::cout << c2 << " using manual *: " << time << std::endl;

  c2 = { 0, 0 };
  t0 = std::chrono::steady_clock::now();
  for( size_t i = 0; i < 10000; ++i ) {
     for( size_t j = 0; j < N - 1; ++j ) {
        c2 += inbuf[ j ] * inbuf[ j + 1 ];
     }
  }
  t1 = std::chrono::steady_clock::now();
  time = ( std::chrono::duration< float >( t1 - t0 ) ).count();
  std::cout << c2 << " using stdlib *: " << time << std::endl;
  return 0;
}

这是输出:

(-2.45689e+07,-134386) using manual *: 0.109344
(-2.45689e+07,-134386) using stdlib *: 5.4286

编辑:鉴于评论中人们的结果不同,我已经使用各种编译选项进行了更多测试。事实证明,-mfma-mavx开关会导致&#34; stdlib&#34;版本太慢了。 -mfma开关提供&#34;手册&#34;版本a~25%的性能提升,但减慢了&#34; stdlib&#34;版本大约13x:

cris@carrier:~/tmp/tests> g++ complex_test.cpp -o complex_test -O3 -std=c++11
cris@carrier:~/tmp/tests> ./complex_test                                     
(-2.45689e+07,-134386) using manual *:0.138276
(-2.45689e+07,-134386) using stdlib *:0.412056
cris@carrier:~/tmp/tests> g++ complex_test.cpp -o complex_test -O3 -mfma -std=c++11 
cris@carrier:~/tmp/tests> ./complex_test                                                  
(-2.45689e+07,-134386) using manual *:0.106551
(-2.45689e+07,-134386) using stdlib *:5.37662

我也尝试过clang-800(Mac OS),并没有看到这种极端减速。 Mac上的g ++ - 5与Linux上的g ++ - 5相同。也许我发现了编译器错误?

1 个答案:

答案 0 :(得分:0)

我遇到了同样的问题,显然在Visual C ++中,复杂计算的性能降低了。以我为例,我是在Visual C ++的调试模式下进行时间测量的。切换到释放模式后,与双重计算相比,时间是合理的(考虑到复杂的操作包括多个双重计算)。