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函数解决频繁调用小函数大量消耗栈空间的问题。
- #include "svm.h"
- int libsvm_version = LIBSVM_VERSION;
-
- typedef float Qfloat;
- typedef signed char schar;
-
- //inline函数解决频繁调用小函数大量消耗栈空间;static函数为静态函数/或内部函数,指函数的调用范围只局限于本文件
- #ifndef min
- template <class T> static inline T min(T x,T y) { return (x<y)?x:y; }
- #endif
- #ifndef max
- template <class T> static inline T max(T x,T y) { return (x>y)?x:y; }
- #endif
- template <class T> static inline void swap(T& x, T& y) { T t=x; x=y; y=t; }
下面这个是clone函数(
一个彻底克隆函数,操做结束后,内部的全部数据和指针彻底同样),刚开始看的时候对clone的形参T*& dst不太了解,后来才知道这是指针的引用,就是说在函数里面指针的改变等同于形参的改变。关于
memcpy和*&的具体解释我参看个人博文
常见的C++知识 。
- template <class S, class T> static inline void clone(T*& dst, S* src, int n)
- {
- dst = new T[n];
- memcpy((void *)dst,(void *)src,sizeof(T)*n);
- }
下面这个是幂次函数,写得挺好的,
对幂次为偶数有优化。当为powi(3,5)时,是这样的3*(81),即把3^5=3*(3^4)
- static inline double powi(double base, int times)
- {
- double tmp = base, ret = 1.0;
-
- for(int t=times; t>0; t/=2)
- {
- if(t%2==1) ret*=tmp;
- tmp = tmp * tmp;
- }
- return ret;
- }
如下几个是调试信息输出
- static void print_string_stdout(const char *s)
- {
- fputs(s,stdout);
- fflush(stdout);
- }
- static void (*svm_print_string) (const char *) = &print_string_stdout;
-
- #if 1
- static void info(const char *fmt,...)
- {
- char buf[BUFSIZ];
- va_list ap;
- va_start(ap,fmt);
- vsprintf(buf,fmt,ap);
- va_end(ap);
- (*svm_print_string)(buf);
- }
- #else
- static void info(const char *fmt,...) {}
- #endif
函数指针专题
在libsvm中有以下代码:oop
- static void print_string_stdout(const char *s)
- {
- fputs(s,stdout);
- fflush(stdout);
- }
- static void (*svm_print_string) (const char *) = &print_string_stdout;
我在论坛中曾经发帖:学习

看了Pump每天学习同窗的回复,我才回想起来:第六行那原来是个函数指针,平时没用到,就给忘了,只能拿出教材从新来学习一遍:优化
函数指针是指向函数而非指向对象的指针。像其余指针同样,函数指针也指向某个特定的类型。函数类型由其返回类型以及形参表肯定,而与函数名无关:ui
- // pf points to function returning bool thar takes two const string references
- bool (*pf) (const string &, const string &);
这个语句将pf声明为指向函数的指针,它所指向的函数带有两个const string &类型的形参和bool类型的返回值。spa
注意:*pf两侧的圆括号是必需的,若没有,则就不是函数指针了。.net
- // declares a function named pf that returns a bool*
- bool *pf (const string &, const string &)
typedef简化函数指针的定义
函数指针类型至关冗长。使用typedef为指针类型定义同义词,可将函数指针的使用大大简化
- typedef bool (*cmpFn)(const string &, const string &)
该定义表示cmpFn是一种指向函数的指针类型的名字。该指针类型为:“指向返回bool类型并带有两个const string 引用形参的函数的指针”。在要使用这种函数指针类型时,只需直接使用cmpFn便可,没必要每次都把整个函数类型声明所有写出来。
经过指针调用函数
指向函数的指针可用于调用它所指向的函数,能够不须要使用解引用操做符,直接经过指针调用函数:
- bool lengthCmp(const string&, const string &);
- cmpFn pf = lengthCmp;
- lengthCmp=("hi","bye");//direct call
- pf("hi","bye");//equivalent call: pf1 implicitly dereferenced
- (*pf)("hi","bye");//equivalent call: pf1 explicitly dereferenced