libsvm代碼閱讀(2):svm.cpp淺談和函數指針

svm.cpp淺談

svm.cpp總共有3159行代碼,實現了svm算法的核心功能,裏面總共有Cache、Kernel、ONE_CLASS_Q、QMatrix、Solver、Solver_NU、SVC_Q、SVR_Q 8個類(以下圖1所示),而它們之間的繼承和組合關係如圖二、圖3所示。在這些類中Cache、Kernel、Solver是核心類,對整個算法起支撐做用。在之後的博文中咱們將對這3個核心類作重點註解分析,另外還將對svm.cpp中的svm_train函數作一個註解分析。web

圖1算法


 圖2app


圖3函數


下面先看看svm.cpp的前幾行代碼,主要是幾個inline函數,inline函數解決頻繁調用小函數大量消耗棧空間的問題
[cpp]   view plain copy 在CODE上查看代碼片 派生到個人代碼片
<EMBED id=ZeroClipboardMovie_1 height=18 name=ZeroClipboardMovie_1 type=application/x-shockwave-flash align=middle pluginspage=http://www.macromedia.com/go/getflashplayer width=18 src=http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf wmode="transparent" flashvars="id=1&width=18&height=18" allowfullscreen="false" allowscriptaccess="always" bgcolor="#ffffff" quality="best" menu="false" loop="false">
  1. #include "svm.h"  
  2. int libsvm_version = LIBSVM_VERSION;  
  3.   
  4. typedef float Qfloat;  
  5. typedef signed char schar;  
  6.   
  7. //inline函數解決頻繁調用小函數大量消耗棧空間;static函數爲靜態函數/或內部函數,指函數的調用範圍只侷限於本文件  
  8. #ifndef min  
  9. template <class T> static inline T min(T x,T y) { return (x<y)?x:y; }  
  10. #endif  
  11. #ifndef max  
  12. template <class T> static inline T max(T x,T y) { return (x>y)?x:y; }  
  13. #endif  
  14. template <class T> static inline void swap(T& x, T& y) { T t=x; x=y; y=t; }  

下面這個是clone函數( 一個徹底克隆函數,操做結束後,內部的全部數據和指針徹底同樣),剛開始看的時候對clone的形參T*& dst不太瞭解,後來才知道這是指針的引用,就是說在函數裏面指針的改變等同於形參的改變。關於 memcpy和*&的具體解釋我參看個人博文  常見的C++知識 。
[cpp]   view plain copy 在CODE上查看代碼片 派生到個人代碼片
<EMBED id=ZeroClipboardMovie_2 height=18 name=ZeroClipboardMovie_2 type=application/x-shockwave-flash align=middle pluginspage=http://www.macromedia.com/go/getflashplayer width=18 src=http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf wmode="transparent" flashvars="id=2&width=18&height=18" allowfullscreen="false" allowscriptaccess="always" bgcolor="#ffffff" quality="best" menu="false" loop="false">
  1. template <class S, class T> static inline void clone(T*& dst, S* src, int n)  
  2. {  
  3.     dst = new T[n];  
  4.     memcpy((void *)dst,(void *)src,sizeof(T)*n);  
  5. }  

下面這個是冪次函數,寫得挺好的, 對冪次爲偶數有優化。當爲powi(3,5)時,是這樣的3*(81),即把3^5=3*(3^4)
[cpp]   view plain copy 在CODE上查看代碼片 派生到個人代碼片
<EMBED id=ZeroClipboardMovie_3 height=18 name=ZeroClipboardMovie_3 type=application/x-shockwave-flash align=middle pluginspage=http://www.macromedia.com/go/getflashplayer width=18 src=http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf wmode="transparent" flashvars="id=3&width=18&height=18" allowfullscreen="false" allowscriptaccess="always" bgcolor="#ffffff" quality="best" menu="false" loop="false">
  1. static inline double powi(double base, int times)  
  2. {  
  3.     double tmp = base, ret = 1.0;  
  4.   
  5.     for(int t=times; t>0; t/=2)  
  6.     {  
  7.         if(t%2==1) ret*=tmp;  
  8.         tmp = tmp * tmp;  
  9.     }  
  10.     return ret;  
  11. }  

如下幾個是調試信息輸出
[cpp]   view plain copy 在CODE上查看代碼片 派生到個人代碼片
<EMBED id=ZeroClipboardMovie_4 height=18 name=ZeroClipboardMovie_4 type=application/x-shockwave-flash align=middle pluginspage=http://www.macromedia.com/go/getflashplayer width=18 src=http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf wmode="transparent" flashvars="id=4&width=18&height=18" allowfullscreen="false" allowscriptaccess="always" bgcolor="#ffffff" quality="best" menu="false" loop="false">
  1. static void print_string_stdout(const char *s)  
  2. {  
  3.     fputs(s,stdout);  
  4.     fflush(stdout);  
  5. }  
  6. static void (*svm_print_string) (const char *) = &print_string_stdout;  
  7.   
  8. #if 1  
  9. static void info(const char *fmt,...)  
  10. {  
  11.     char buf[BUFSIZ];  
  12.     va_list ap;  
  13.     va_start(ap,fmt);  
  14.     vsprintf(buf,fmt,ap);  
  15.     va_end(ap);  
  16.     (*svm_print_string)(buf);  
  17. }  
  18. #else  
  19. static void info(const char *fmt,...) {}  
  20. #endif  

函數指針專題

在libsvm中有以下代碼:oop

[cpp]   view plain copy 在CODE上查看代碼片 派生到個人代碼片
<EMBED id=ZeroClipboardMovie_5 height=18 name=ZeroClipboardMovie_5 type=application/x-shockwave-flash align=middle pluginspage=http://www.macromedia.com/go/getflashplayer width=18 src=http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf wmode="transparent" flashvars="id=5&width=18&height=18" allowfullscreen="false" allowscriptaccess="always" bgcolor="#ffffff" quality="best" menu="false" loop="false">
  1. static void print_string_stdout(const char *s)  
  2. {  
  3.     fputs(s,stdout);  
  4.     fflush(stdout);  
  5. }  
  6. static void (*svm_print_string) (const char *) = &print_string_stdout;  

我在論壇中曾經發帖:學習

看了Pump每天學習同窗的回覆,我纔回想起來:第六行那原來是個函數指針,平時沒用到,就給忘了,只能拿出教材從新來學習一遍:優化

函數指針是指向函數而非指向對象的指針。像其餘指針同樣,函數指針也指向某個特定的類型。函數類型由其返回類型以及形參表肯定,而與函數名無關:ui

[cpp]   view plain copy 在CODE上查看代碼片 派生到個人代碼片
<EMBED id=ZeroClipboardMovie_6 height=18 name=ZeroClipboardMovie_6 type=application/x-shockwave-flash align=middle pluginspage=http://www.macromedia.com/go/getflashplayer width=18 src=http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf wmode="transparent" flashvars="id=6&width=18&height=18" allowfullscreen="false" allowscriptaccess="always" bgcolor="#ffffff" quality="best" menu="false" loop="false">
  1. // pf points to function returning bool thar takes two const string references  
  2. bool (*pf) (const string &, const string &);  

這個語句將pf聲明爲指向函數的指針,它所指向的函數帶有兩個const string &類型的形參和bool類型的返回值。spa

注意*pf兩側的圓括號是必需的,若沒有,則就不是函數指針了。.net

[cpp]   view plain copy 在CODE上查看代碼片 派生到個人代碼片
<EMBED id=ZeroClipboardMovie_7 height=18 name=ZeroClipboardMovie_7 type=application/x-shockwave-flash align=middle pluginspage=http://www.macromedia.com/go/getflashplayer width=18 src=http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf wmode="transparent" flashvars="id=7&width=18&height=18" allowfullscreen="false" allowscriptaccess="always" bgcolor="#ffffff" quality="best" menu="false" loop="false">
  1. // declares a function named pf that returns a bool*  
  2. bool *pf (const string &, const string &)  


typedef簡化函數指針的定義

函數指針類型至關冗長。使用typedef爲指針類型定義同義詞,可將函數指針的使用大大簡化

[cpp]   view plain copy 在CODE上查看代碼片 派生到個人代碼片
<EMBED id=ZeroClipboardMovie_8 height=18 name=ZeroClipboardMovie_8 type=application/x-shockwave-flash align=middle pluginspage=http://www.macromedia.com/go/getflashplayer width=18 src=http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf wmode="transparent" flashvars="id=8&width=18&height=18" allowfullscreen="false" allowscriptaccess="always" bgcolor="#ffffff" quality="best" menu="false" loop="false">
  1. typedef bool (*cmpFn)(const string &, const string &)  

該定義表示cmpFn是一種指向函數的指針類型的名字。該指針類型爲:「指向返回bool類型並帶有兩個const string 引用形參的函數的指針」。在要使用這種函數指針類型時,只需直接使用cmpFn便可,沒必要每次都把整個函數類型聲明所有寫出來。


經過指針調用函數

指向函數的指針可用於調用它所指向的函數,能夠不須要使用解引用操做符,直接經過指針調用函數:

[cpp]   view plain copy 在CODE上查看代碼片 派生到個人代碼片
<EMBED id=ZeroClipboardMovie_9 height=18 name=ZeroClipboardMovie_9 type=application/x-shockwave-flash align=middle pluginspage=http://www.macromedia.com/go/getflashplayer width=18 src=http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf wmode="transparent" flashvars="id=9&width=18&height=18" allowfullscreen="false" allowscriptaccess="always" bgcolor="#ffffff" quality="best" menu="false" loop="false">
  1. bool lengthCmp(const string&, const string &);  
  2. cmpFn pf = lengthCmp;  
  3. lengthCmp=("hi","bye");//direct call  
  4. pf("hi","bye");//equivalent call: pf1 implicitly dereferenced  
  5. (*pf)("hi","bye");//equivalent call: pf1 explicitly dereferenced
相關文章
相關標籤/搜索