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所示),而它们之间的继承和组合关系如图2、图3所示。在这些类中Cache、Kernel、Solver是核心类,对整个算法起支撑作用。在以后的博文中我们将对这3个核心类做重点注解分析,另外还将对svm.cpp中的svm_train函数做一个注解分析。

图1

图2

图3

下面先看看svm.cpp的前几行代码,主要是几个inline函数,inline函数解决频繁调用小函数大量消耗栈空间的问题。

[cpp]   view plain copy  

<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. typedef float Qfloat;
  4. typedef signed char schar;
  5. //inline函数解决频繁调用小函数大量消耗栈空间;static函数为静态函数/或内部函数,指函数的调用范围只局限于本文件
  6. #ifndef min
  7. template <class T> static inline T min(T x,T y) { return (x<y)?x:y; }
  8. #endif
  9. #ifndef max
  10. template <class T> static inline T max(T x,T y) { return (x>y)?x:y; }
  11. #endif
  12. 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  

<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  

<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. for(int t=times; t>0; t/=2)
  5. {
  6. if(t%2==1) ret*=tmp;
  7. tmp = tmp * tmp;
  8. }
  9. return ret;
  10. }

以下几个是调试信息输出

[cpp]   view plain copy  

<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. #if 1
  8. static void info(const char *fmt,...)
  9. {
  10. char buf[BUFSIZ];
  11. va_list ap;
  12. va_start(ap,fmt);
  13. vsprintf(buf,fmt,ap);
  14. va_end(ap);
  15. (*svm_print_string)(buf);
  16. }
  17. #else
  18. static void info(const char *fmt,...) {}
  19. #endif

函数指针专题

在libsvm中有如下代码:

[cpp]   view plain copy  

<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天天学习同学的回复,我才回想起来:第六行那原来是个函数指针,平时没用到,就给忘了,只能拿出教材重新来学习一遍:

函数指针是指向函数而非指向对象的指针。像其他指针一样,函数指针也指向某个特定的类型。函数类型由其返回类型以及形参表确定,而与函数名无关:

[cpp]   view plain copy  

<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类型的返回值。

注意:*pf两侧的圆括号是必需的,若没有,则就不是函数指针了。

[cpp]   view plain copy  

<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  

<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  

<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
时间: 2024-12-30 01:29:20

libsvm代码阅读(2):svm.cpp浅谈和函数指针(转)的相关文章

浅谈RAII&智能指针

关于RAII,官方给出的解释是这样的"资源获取就是初始化".听起来貌似不是很懂的哈,其实说的通俗点的话就是它是一种管理资源,避免内存泄漏的一种方法.它可以保证在各种情况下,当你对对象进行使用时先通过构造函数来进行资源的分配和初始化,最后通过析构函数来进行清理,有效的保证了资源的正确分配和释放.(特别是在异常中,因为异常往往会改变代码正确的执行顺序,这就很容易引起资源管理的混乱和内存的泄漏) 其中智能指针就是RAII的一种实现模式,所谓的智能就是它可以自动化的来管理它所指向那份空间的资源

浅谈javascript函数劫持

http://www.xfocus.net/articles/200712/963.html 浅谈javascript函数劫持 文章提交:hkluoluo (luoluonet_at_hotmail.com) by luoluo on 2007-11-30 luoluonet_at_yahoo.cn http://www.ph4nt0m.org 一.概述 javascript函数劫持,也就是老外提到的javascript hijacking技术.最早还是和剑心同学讨论问题时偶然看到的一段代码,大

开发技术--浅谈Python函数

开发|浅谈Python函数 函数在实际使用中有很多不一样的小九九,我将从最基础的函数内容,延伸出函数的高级用法.此文非科普片~~ 前言 目前所有的文章思想格式都是:知识+情感. 知识:对于所有的知识点的描述.力求不含任何的自我感情色彩. 情感:用我自己的方式,解读知识点.力求通俗易懂,完美透析知识. 正文 首先介绍函数是什么,接着走进函数,并且发现函数的高级使用方法,最后列出常用的Python的内置函数. 函数是什么? 1.函数,在代码执行的是不执行,只有在调用函数的时候才会执行. 2.函数使用

浅谈为什么只有指针能够完成多态及动态转型的一个误区

c++多态由一个函数地址数组Vtable和一个指向Vtable的指针vptr实现. 具体来说,类拥有自己的vtable,类的vtable在编译时刻完成. 每个对象有自己的vptr指针,该指针初始化时指向对象所实现的类的vtable. 关于向上转型的误区: 通常对于向上转型的理解是这样的,当子类对象向上转型(允许隐式)成父类对象时,实际上只是将子类对象暂时看做父类对象,内部的数据并未改变. 对于没有虚函数的对象,这句话是正确的,但是,当引入虚函数后,这样的理解是有问题的,实际上,向上转型的过程中,

转 浅谈C++中指针和引用的区别

浅谈C++中指针和引用的区别 浅谈C++中指针和引用的区别 指针和引用在C++中很常用,但是对于它们之间的区别很多初学者都不是太熟悉,下面来谈谈他们2者之间的区别和用法. 1.指针和引用的定义和性质区别: (1)指针:指针是一个变量,只不过这个变量存储的是一个地址,指向内存的一个存储单元:而引用跟原来的变量实质上是同一个东西,只不过是原变量的一个别名而已.如: int a=1;int *p=&a; int a=1;int &b=a; 上面定义了一个整形变量和一个指针变量p,该指针变量指向a

C++ 浅谈C++中指针和引用

浅谈C++中指针和引用的区别 指针和引用在C++中很常用,但是对于它们之间的区别很多初学者都不是太熟悉,下面来谈谈他们2者之间的区别和用法. 1.指针和引用的定义和性质区别: (1)指针:指针是一个变量,只不过这个变量存储的是一个地址,指向内存的一个存储单元:而引用跟原来的变量实质上是同一个东西,只不过是原变量的一个别名而已.如: int a=1;int *p=&a; int a=1;int &b=a; 上面定义了一个整形变量和一个指针变量p,该指针变量指向a的存储单元,即p的值是a存储单

浅谈intval()函数用法

1 <?php 2 $sql=mysql_query("select count(*) as total from tb_leaveword ",$conn); 3 $infos=mysql_fetch_array($sql); 4 $total=$infos['total']; //获取总留言条数 5 if($total==0){ //如果总留言条数为0,则给出提示 6 echo "<div align=center>对不起,暂无留言!</div&g

【python】浅谈enumerate 函数

enumerate 函数用于遍历序列中的元素以及它们的坐标: >>> for i,j in enumerate(('a','b','c')):  print i,j 0 a 1 b 2 c >>> for i,j in enumerate([1,2,3]):  print i,j 0 1 1 2 2 3 >>> for i,j in enumerate({'a':1,'b':2}):  print i,j 0 a 1 b >>> fo

libsvm代码阅读(1):基础准备与svm.h头文件(转)

libsvm是国立台湾大学Chih-Jen Lin开发的一个SVM的函数库,是当前应用最广泛的svm函数库,从2000年到2010年,该函数库的下载量达到250000之多.它的最新版本是version 3.17,主要是对是svm_group_classes做了修改. 主页:LIBSVM -- A Library for Support Vector Machines 下载地址:zip.file ortar.gz 我下载后的解压文件如下所示: libsvm函数包的组织结构如下: 1.主文件路径:包