為什麼這段C代碼的速度沒有Mathematica和Matlab快?

http://www.forcal.net/sysm/lu1/luhtm/luspeed.htm

就是普通的循環累加,上面的第一個例子,

GCC4.5 使用 -O2:2s ,Matlab2013a:1.1s,Mathematica9:0.78s。

這是什麼原因呢?

Mathematica代碼:

Compile[{},
With[{y = Range[1, 2, 0.0011]},
Table[
Cos[-1. + Sin[1.2 (x + 0.1)^(y/2. - x) +
Cos[-1. + Sin[1.2 (x + 0.2)^(y/3. - x)]]] +
Cos[-1. + Sin[1.2 (x + 0.3)^(y/4. - x)]] +
Cos[-1. + Sin[1.2 (x + 0.4)^(y/5. - x) +
Cos[-1. + Sin[1.2 (x + 0.5)^(y/6. - x)]]] +
Cos[-1. + Sin[1.2 (x + 0.6)^(y/7. - x)]]]],
{x, 0, 1, 0.0011}]
]
][] ~Total~2 // InputForm // AbsoluteTiming

Matlab代碼:

tic;
[x, y] = meshgrid(0: 0.0011: 1, 1: 0.0011: 2);
s = cos(1.0-sin(1.2*(x+0.1).^(y/2.0-x)+...
cos(1.0-sin(1.2*(x+0.2).^(y/3.0-x))))-...
cos(1.0-sin(1.2*(x+0.3).^(y/4.0-x)))-...
cos(1.0-sin(1.2*(x+0.4).^(y/5.0-x)+...
cos(1.0-sin(1.2*(x+0.5).^(y/6.0-x))))-...
cos(1.0-sin(1.2*(x+0.6).^(y/7.0-x)))));
sum(s(:))
toc;


我猜你說的是第一個例子

你寫的C代碼用的是多重循環,而Mathematica和Matlab分別利用了矩陣運算,避免了循環,這些科學計算軟體,使用矩陣運算整體化處理多重循環的時候,採取了很多優化技巧。順便說下,很多寫Matlab程序的人把matlab當成C用是非常愚蠢的。

這個和你自己手寫的多重循環是完全不同的


C語言做科學計算的時候不是這麼用的,不要按做數學題的思路寫C代碼,

要按寫C代碼的思路寫C代碼,無論你的目的是什麼.

如果我記得不錯,GCC在O2的時候調用的sin和pow,都是fpu來算,而matlab里肯定至少用了

SSE2,尤其是像這個測試這種可以很充分地平行化的情況.

而且,你不覺得這個測試對C非常不公平嗎? matlab我用的多些,就拿matlab來說,

[x, y] = meshgrid(0: 0.0011: 1, 1: 0.0011: 2);
首先,這條語句創建了一個x和y的矩陣,其中的所有元素xn和yn都已經被提前計算出來了,
數組(或者說矩陣)的維數也已經被計算出來了.既然計算出了維數,下面的指令里:
x(n)和任意一個x(m)...m!=n又沒有任何關聯,matlab此時不用SIMD簡直沒天理了.

而C不一樣,C不是針對科學計算開發的語言,面對數學它沒那麼聰明,而且事實上你寫的matlab代碼
的邏輯和你給的網頁中的C代碼中的邏輯一點也不一樣,按照matlab的方式,C代碼的邏輯應該是和
matlab一樣,先算出所有出現的x和y,然後按照數組的尺寸進行循環,而且你必須手動調用intrinsics
或者內聯彙編來處理循環內部的元素.這樣才是公平的測試.

本想幫你按照matlab邏輯寫個C版本,但手頭沒有小的SSE版本的sin和pow庫,只好作罷了


大多數時候,Matlab和Mathematica處理數學計算都比你手寫的C語言快。

首先,是你的演算法問題。很多時候你寫的數值演算法不如他們寫的好。畢竟他們更專業。

其次,是代碼優化的問題。針對平台的優化在計算密集型程序裡面相當重要。比如同樣是Intel平台,你使用微軟的編譯器,默認情況下最多會使用SSE2指令優化你的代碼。而他們在數學運算上,普遍使用的是Intel的MKL。這個數學庫會根據你使用的處理器而選擇載入不同的實現版本,這些版本會使用當前處理器上支持的指令集,從而最大化利用你處理器的能力。而使用SSE這類SIMD指令對於矩陣一類計算量大,但流程並不複雜的運算優化是相當大的。

你可以試試用SIMD彙編指令實現你的演算法,或者用intrinsics,很多時候都比你寫的純C代碼更快。


如果只是需要得到計算結果的話,還是優先考慮MATLAB,尤其是當數據量很大的時候,最近手頭的一個項目就是需要對大量的實驗數據進行插值處理,開始也是用C語言寫的代碼,在用小數據測試階段運行良好,但當真正開始處理大量數據的時候總是會出各種各樣的內存問題,寫C代碼我是經驗不足,但周邊有用C寫硬體驅動還做過演算法開發的兄弟幫我處理,前後花了兩周時間還是沒有搞定,大把的時間花在調試上面。

後來換用MATLAB,一天半搞定所有計算問題。關鍵是幾十個文件半個小時全部處理完了,之前的處理方案是用C代碼插值後再導入EXCEL2007使用公式計算插值偏差,還得一個個手工處理,在MATLAB裡面直接一個[r,c]=siae(A),B=diff(A),B./(A(:,c-1)),搞定。

多個文件直接dir,load,save,幾個命令,再利用length,自動計算文件數量,寫個for循環,全部搞定。插值計算griddata,meshgrid結合使用。想想看,這些事情用C語言需要多長時間。


推薦閱讀:

Wolfram Mathematica 有哪些比較好(有特色,有用)的Package?
MATLAB有哪些隱藏功能?
正版的matlab以及mathematica比盜版的優勢是什麼?
為什麼Mathematica中無法Manipulate一個先前定義的變數中的參數?

TAG:編程 | 數學軟體 | MATLAB | WolframMathematica | C編程語言 |