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

 

Copyright (c) prototype, all rights reserved

在不對原文內容(包括作者信息)做任何改動的前提下,歡迎自由轉載。
 
兩年多前寫的內部資料。現在自己把它翻成中文,貼到我的blog上來。
 
近來閒暇時,我用C++和表達式模板(expression template)技術實現了一個複數類(注意:是類,而不是類模板)— Complex。在類型上,它相當於std::complex<float>,但它可以很容易通過一個typedef變成一個與std::complex<double> 或 std::complex<long double>相當的類。在功能上,它實現了各種運算符重載和各種函數。最初設計和實現這個類的目的只是單純的爲了好玩,順便溫故一下已經許久沒碰過的表達式模板技術。在一切必要的功能都實現完畢後,我想到和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<Real>
331
// 表示完成相同數目的運算,std::complex<float> 所需要的tick數。Real 其實就是float的一個typedef。
 
 
測試結果:
 
complex += complex ======
Complex
370
std::complex<Real>
331
 
complex /= complex ======
Complex
500
std::complex<Real>
851
 
complex *= complex ======
Complex
331
std::complex<Real>
330
 
complex += real ======
Complex
341
std::complex<Real>
330
 
complex *= real ======
Complex
331
std::complex<Real>
320
 
complex /= real ======
Complex
832
std::complex<Real>
821
 
complex + complex ======
Complex
330
std::complex<Real>
341
 
complex * complex ======
Complex
330
std::complex<Real>
7501
 
complex / complex ======
Complex
340
std::complex<Real>
401
 
complex + real ======
Complex
330
std::complex<Real>
341
 
complex * real ======
Complex
2383
std::complex<Real>
7361
 
complex / real ======
Complex
330
std::complex<Real>
381
 
real / complex ======
Complex
681
std::complex<Real>
1051
 
sin( complex ) ======
Complex
9494
std::complex<Real>
10826
 
tan( complex ) ======
Complex
6139
std::complex<Real>
22732
 
sinh( complex ) ======
Complex
6720
std::complex<Real>
10845
 
cosh( complex ) ======
Complex
6710
std::complex<Real>
10836
 
tanh( complex ) ======
Complex
7430
std::complex<Real>
22423
 
pow( complex, real ) ======
Complex
7981
std::complex<Real>
11276
 
pow( real, complex ) ======
Complex
6069
std::complex<Real>
8963
 
pow( complex, complex ) ======
Complex
11727
std::complex<Real>
14020
 
d[i] = (a + b * c) * i ======
Complex
391
std::complex<Real>
560
 
 
d[i] = a + b * 2 + c / 3 - b * i + c * i ======
Complex
621
complex<Real>
1643
Pure C code
871
 
d[i] = (((a + b) * c / a) * (c * i - a) + a * c) * i / b ======
Complex
2223
std::complex<Real>
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.本文不涉及高性能計算程序應當用何種語言進行編寫的問題。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章