在高性能计算中慎用C++ std::complex

 

Copyright (c) prototype, all rights reserved

在不对原文内容(包括作者信息)做任何改动的前提下,欢迎自由转载。
 
两年多前写的内部资料。现在自己把它翻成中文,贴到我的blog上来。
 
近来闲暇时,我用C++和表达式模板(expression template)技术实现了一个复数类(注意:是类,而不是类模板)— Complex。在类型上,它相当于std::complex,但它可以很容易通过一个typedef变成一个与std::complex 或 std::complex相当的类。在功能上,它实现了各种运算符重载和各种函数。最初设计和实现这个类的目的只是单纯的为了好玩,顺便温故一下已经许久没碰过的表达式模板技术。在一切必要的功能都实现完毕后,我想到和std::complex比较一下运行速度,结果却令人非常吃惊。原始结果直接copy/paste在下面。
 
一些说明:
1.测试条件:运行平台为PIII 750,WinXP Home/Cygwin。编译器为gcc 3.3.2。优化条件为 -O3 -NDEBUG。
2.程序输出格式举例说明如下:
 
complex += complex ======
// 表示比较的内容为:+= 运算符。
 
Complex
370
// 表示完成一定数目(10000000)运算,Complex所需要的tick数(越小越好/快)。
 
std::complex
331
// 表示完成相同数目的运算,std::complex 所需要的tick数。Real 其实就是float的一个typedef。
 
 
测试结果:
 
complex += complex ======
Complex
370
std::complex
331
 
complex /= complex ======
Complex
500
std::complex
851
 
complex *= complex ======
Complex
331
std::complex
330
 
complex += real ======
Complex
341
std::complex
330
 
complex *= real ======
Complex
331
std::complex
320
 
complex /= real ======
Complex
832
std::complex
821
 
complex + complex ======
Complex
330
std::complex
341
 
complex * complex ======
Complex
330
std::complex
7501
 
complex / complex ======
Complex
340
std::complex
401
 
complex + real ======
Complex
330
std::complex
341
 
complex * real ======
Complex
2383
std::complex
7361
 
complex / real ======
Complex
330
std::complex
381
 
real / complex ======
Complex
681
std::complex
1051
 
sin( complex ) ======
Complex
9494
std::complex
10826
 
tan( complex ) ======
Complex
6139
std::complex
22732
 
sinh( complex ) ======
Complex
6720
std::complex
10845
 
cosh( complex ) ======
Complex
6710
std::complex
10836
 
tanh( complex ) ======
Complex
7430
std::complex
22423
 
pow( complex, real ) ======
Complex
7981
std::complex
11276
 
pow( real, complex ) ======
Complex
6069
std::complex
8963
 
pow( complex, complex ) ======
Complex
11727
std::complex
14020
 
d[i] = (a + b * c) * i ======
Complex
391
std::complex
560
 
 
d[i] = a + b * 2 + c / 3 - b * i + c * i ======
Complex
621
complex
1643
Pure C code
871
 
d[i] = (((a + b) * c / a) * (c * i - a) + a * c) * i / b ======
Complex
2223
std::complex
2514
 
 
总结:
1.除了个别情况(此时二者速度相当),std::complex 总是慢于Complex。
2.对某些运算,如,complex * real , tan, tanh,差别竟高达3倍。
3.对单个双目算术运算,似乎二者无差别(complex * complex除外)。
4.对complex * complex,二者不可思议地差了20倍。原因不明。
5.对中等复杂的算术表达式,如:d[i] = a + b * 2 + c / 3 - b * i + c * i,std::complex比Complex慢150+%。而Complex 与手写的C代码相当。
6.对相当复杂的算术表达式,如:d[i] = (((a + b) * c / a) * (c * i - a) + a * c) * i / b,std::complex比Complex稍慢,但二者相差不太大。
 
总之,即使在这样一个典型的实现里(即:gcc 3.3.2),std::complex似乎仍有不少优化空间。对大量使用复数的高性能计算C++程序,选择使用std::complex时应该慎重。
 
最后,为了避免某些误解带来的不必要战火,本人要强调的是,本文的数据和结论仅对本人使用的编译/运行环境适用。本文的结论并   不   意味着下面这些观点:
1.std::complex  一定   比自己写的复数类或C代码要慢。
2.std::complex 不适合在   任何 程序中使用。
3.任何   高性能计算C++程序不应当使用std::complex。
4.本文不涉及高性能计算程序应当用何种语言进行编写的问题。

你可能感兴趣的:(C++)