QQ登录

只需要一步,快速开始

 注册地址  找回密码
查看: 1800|回复: 4
打印 上一主题 下一主题

[问题求助] matlab中关于提高for循环速度的问题

[复制链接]
字体大小: 正常 放大

4

主题

11

听众

89

积分

升级  88.42%

  • TA的每日心情
    开心
    2015-1-31 19:30
  • 签到天数: 33 天

    [LV.5]常住居民I

    跳转到指定楼层
    1#
    发表于 2014-8-17 20:02 |只看该作者 |倒序浏览
    |招呼Ta 关注Ta
    如何提高下面程序的运算速度?
    其中单元阵列A和B中存的是字符串,该程序的目的是寻找A和B中相同字符串的对数,即m的大小(A和B都是一行、50000列的cell)

    m=0;
    for i=1:50000

         for t=1:50000

          m=m+strncmp(A{1,t},B{1,i},5);

         end

    end
    m


    zan
    转播转播0 分享淘帖0 分享分享0 收藏收藏0 支持支持0 反对反对0 微信微信

    13

    主题

    9

    听众

    333

    积分

    升级  11%

  • TA的每日心情

    2015-2-5 18:17
  • 签到天数: 89 天

    [LV.6]常住居民II

    自我介绍
    对acm、数模比较有兴趣

    群组国赛讨论

    回复

    使用道具 举报

    90

    主题

    105

    听众

    9483

    积分

  • TA的每日心情

    2017-1-30 23:35
  • 签到天数: 318 天

    [LV.8]以坛为家I

    2010挑战赛参赛者

    2011挑战赛参赛者

    2012挑战赛参赛者

    2013挑战赛参赛者

    社区QQ达人

    群组物联网工程师培训

    群组Matlab讨论组

    群组2013认证赛C题讨论群组

    群组数学建模

    群组2013认证赛A题讨论群组

    回复

    使用道具 举报

    90

    主题

    105

    听众

    9483

    积分

  • TA的每日心情

    2017-1-30 23:35
  • 签到天数: 318 天

    [LV.8]以坛为家I

    2010挑战赛参赛者

    2011挑战赛参赛者

    2012挑战赛参赛者

    2013挑战赛参赛者

    社区QQ达人

    群组物联网工程师培训

    群组Matlab讨论组

    群组2013认证赛C题讨论群组

    群组数学建模

    群组2013认证赛A题讨论群组

    最近MATLAB作实验,需要对高维矩阵的每个元素进行操作,MATLAB矩阵运算的优势无法发挥出来,只能用若干循环来实现,效率很低。想到了mex中实现C接口来使用C完成部分工作,可以极大提高效率,于是尝试利用mex接口来完成这部分工作。找了若干参考书,但发现写的并不好,不适合没有mex经验的人使用,可是会mex的人只需依靠MATLAB帮助即可完成工作,对他们来说更没有什么用处。于是写点自己在windows平台下适用MATLAB的mex接口的体会。
    mex的适用情况:需要大量循环或者遍历,不想改写已有的C模块,这些情况下适用mex接口比较合适。
    mex的环境要求:已安装MATLAB,已安装合适的C编译器。
    mex使用:
    首先在MATLAB中使用mex -setup设置工作环境和相应的配置文件。mex其他参数详见帮助。
    对于需要使用mex接口的程序,文件的扩展名需要为c/cpp,然后用mex filename进行编译。编译完成后会生成dll文件(7.1之前)或者mexw32文件(7.1之后)。
    编译完成后,即可像m文件一样适用mex。
    多多发帖,受益多多
    回复

    使用道具 举报

    90

    主题

    105

    听众

    9483

    积分

  • TA的每日心情

    2017-1-30 23:35
  • 签到天数: 318 天

    [LV.8]以坛为家I

    2010挑战赛参赛者

    2011挑战赛参赛者

    2012挑战赛参赛者

    2013挑战赛参赛者

    社区QQ达人

    群组物联网工程师培训

    群组Matlab讨论组

    群组2013认证赛C题讨论群组

    群组数学建模

    群组2013认证赛A题讨论群组

    mex接口的结构:
    //////////////////////////////////////////////
    #include "mex.h"
    ///////////////////////////
    // Computational Routine //
    ///////////////////////////
    // interface & function declaration
    return_type myFunc1(parameter1, parameter2, ...);
    return_type myFunc2(parameter1, parameter2, ...);
    ...
    // interface & function defination, implementation
    void myMex(parameter1, parameter2, ...){
        statements
    }
    return_type myFunc1(parameter1, parameter2, ...){
        statements
    }
    return_type myFunc2(parameter1, parameter2, ...){
        statements
    }
    ...
    /////////////////////
    // Gateway Routine //
    /////////////////////
    void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]){
        ...
        myMex(parameter list);
    }
    //////////////////////////////////////////////
    调用mex时,MATLAB将输入的数据通过入口子程序赋给输入参数指针,同时创建由输出参数指针指向的输出矩阵,然后将这些指针作为计算子程序的参数传递到计算子程序进行计算。
    mexFunction在调用C函数时,直接使用指针传递参数是比较方便的,一方面需要计算的结果往往是一个矩阵而不是一个数,另一方面以值传递值返回的方式,同样需要赋值给mex接口的指针。
    在mexFunction的参数中:
    nlhs表示输出参数的个数
    nrhs表示输入参数的个数
    类型为mxArray的指针数组,用于指向输出的每个参数
    类型为mxArray的指针数组,用于指向输入的每个参数
    为了mex的正确执行,也是良好编程习惯的要求,需要对输入参数和输出参数进行个数和类型的检查:
    mxGetClassID //获得指针所指变量类型
    mxIsNumeric, mxIsCell等,检查指针所指变量是否为符合某种要求的变量类型。更多可查阅帮助。
    参数检查过程中可使用mexErrMsgTxt输出错误信息。
    mxGetM, mxGetN,获得矩阵的行数和列数
    mxGetDimensions,获得矩阵维数
    mxGetPr,mxGetPi,获得矩阵实数部分、虚数部分的指针
    mxGetString, 获得字符串内容
    mxGetElementSize, 获得存储矩阵元素所需要的字节数
    mxCalloc,内存分配。用mxCalloc不用calloc和malloc,因为mxCalloc会自动释放内存,不需要手动free了。
    mxCreateString, 创建1*N的字符串矩阵
    mxCreateDoubleMatrix, 创建2维双精度浮点矩阵,可以是实数(mxREAL)或者复数(mxCOMPLEX)
    mxCreateStructArray, 创建N维结构体矩阵
    mxCreateCellMatrix, 创建二维单元矩阵
    mxCreateNumericArray,创建n维数值矩阵
    mexPrintf, 重新封装的printf
    mxSetFiled, 设置结构体矩阵的域
    mxSetCell, 设置单元矩阵的单元值
    mxSetPr, 设置矩阵实数值
    mxSetPi, 设置矩阵虚数值
    mxCallMATLAB, 调用MATLAB中其他内建函数、自定义M文件、mex文件。
    具体使用方法可查阅MATLAB帮助。
    使用mex时的注意事项:
    1.MATLAB调用mex接口时,将参数个数及参数指针传入接口子程序,由接口子程序完成指针和调用变量的赋值、输出数据的内存空间分配,接口子程序再将参数指针或经过赋值的变量作为参数传递给C的计算子程序,完成调用过程。调用时应注意指针所指对象的正确性,为处理正确最好做相应的强制类型转换。
    2.mex并不便于调试,因此应在C的IDE中用测试集调试后再放入mex文件中。
    3.MATLAB中指向二维及高维数组的指针递增方式是按行递增的,而C中是按列递增的,因此计算index时要注意位置。

    下面给个我的例子:
    /////////////////////////////
    #include "mex.h"
    int LSB(int pixel);
    int tier_score(int s_1,int s_2,int x_1,int x_2);
    int add_sub_select(int pixel_1,int pixel_2);
    void cost_matrix_gen_c(double *output,double *x,double *len_x,double *y,double *len_y){
        int i,j;
        int s_1,s_2,x_1,x_2;
        for (j=0;j<*len_y;j++){
            x_1 = (int)*(y+j*2);
            x_2 = (int)*(y+j*2+1);
            for (i=0;i<*len_x;i++){
                s_1 = (int)*(x+i*2);
                s_2 = (int)*(x+i*2+1);
                *(output++)=tier_score(s_1,s_2,x_1,x_2);
            }
        }
    }
    int tier_score(int s_1,int s_2,int x_1,int x_2){
        int score;
        if (s_1==LSB(x_1)){
            if (s_2==add_sub_select(x_1,x_2)){
                score = 20;
            }
            else{
                score = 0;
            }
        }
        else{
            score = 0;
        }
        return score;
    }
    int LSB(int pixel){
        return pixel%2;
    }
    int add_sub_select(int pixel_1,int pixel_2){
        return LSB((int)pixel_1/2 + pixel_2);
    }
    void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]){
        double *y,*x,*output,*len_x,*len_y;
        int n_row,n_column;
       
        if (nrhs != 4 || nlhs != 1){
            mexErrMsgTxt("invalid number of input/output arguments!");
        }
        //参数个数检查
        n_row = mxGetM(prhs[0])>mxGetN(prhs[0]) ? mxGetM(prhs[0]) : mxGetN(prhs[0]);
        //获得输入向量元素个数
        n_column = mxGetM(prhs[2])>mxGetN(prhs[2]) ? mxGetM(prhs[2]) : mxGetN(prhs[2]);
        //获得输入向量元素个数
        n_row = n_row/2;
        n_column = n_column/2;
       
        plhs[0] = mxCreateDoubleMatrix(n_row,n_column,mxREAL);
        //建立n_row*n_column大小的输出矩阵
        output = mxGetPr(plhs[0]);   
        x=mxGetPr(prhs[0]);
        len_x=mxGetPr(prhs[1]);
        y=mxGetPr(prhs[2]);
        len_y=mxGetPr(prhs[3]);
        //获得输入、输出指针   
        cost_matrix_gen_c(output,x,len_x,y,len_y);
        //调用计算函数
    }


    以前我写过一篇文章,详细的介绍过MEX的格式,语法,编译,调试等。可惜记不清放在哪里了。而最近又用到MEX编程,所以只能重新温习一番。时间有限,只记下简要流程和注意事项,以便往后查询之需。
    1. MEX的编写格式
    写MEX程序其实就是写一个DLL程序,所以你可以使用C,C++,Fortran等多种编程语言来写。
    编写MEX程序的编辑器可以使用MATLAB的代码编辑器,也可使用自己的C++编辑器,如VS2008等。
    用MATLAB的编辑器的好处是,MEX函数会加粗高亮显示,这给程序编写带来便利,可惜无法动态调试。如用VC即可编译也可调试,比较方便。mex的编译结果实际上就是一个带输出函数mexFunction 的dll文件,所以会用VC编写和调试dll,就会用VC编写和调试MEX程序。
    a. MEX文件格式
    #include "mex.h"
    void mexFunction( int nlhs, mxArray *plhs[],
                      int nrhs, const mxArray *prhs[] )
    {
    }
    四个参数分别用来输出和输入数据: nlhs 输出参数个数,plhs 输出参数指针 (nrhs和prhs是输入参数相关的)。
    注意: 我们对输出和输入参数的操作都是通过指针的方式进行的。(这点很容易理解,因为我们的计算结果是需要传递给MATLAB的,实际上我们传递的不是数据,而是指针。MATLAB可以通过这些指针,访问内存中的数据。)
    b. 操作输入数据
    对输入数据进行操作,需要通过MEX函数mxGetPr 得到数据的指针地址。 mxGetM 和 mxGetN 得到矩阵数据的行和列 (返回整数)。对于实矩阵,我们可以定义 double *M; 来对实矩阵数据操作。如:
    double *M;
    int m,n;
    // 指针指向第一个参数的数据地址
    M = mxGetPr(prhs[0]);
    m = mxGetM(prhs[0]);
    n = mxGetN(prhs[0]);
    需要注意的是,MATLAB矩阵数据的存储顺序是"从上到下,从左到右"的,这点和Fortran是一样的。也就是说对于MATLAB的m x n的矩阵A。 A(1,1) 就是 *M,A(2,1) 就是 *(M+1) ,以此类推,A(i,j) 就是 *(M + m*(j-1) + (i-1)).
    注意: MATLAB的指标从1开始,C的指标从0开始。
    c. 操作输出数据
    对于输出数据,我们需要首先分配内存空间,有专门的mex函数可以使用,如:
    plhs[0] = mxCreateDoubleMatrix(m,n, mxREAL); //生成m x n 的实矩阵。
    同输入数据一样,要对输出数据操作,我们也需要一个指向数据的指针变量,如
    double *A;
    A = mxGetPr(plhs[0]);
    下面介绍一下如何使用VS2008编写MEX并编译调试。
    2. VC中编写MEX
    打开VS2008, 新建项目, 选择MFC DLL.
    a. 配置项目属性
    打开项目属性配置页,C++ -> 附加包含目录 加入MATLAB安装目录下的 \extern\include 路径。
    连接器 -> 附加库目录 加入MATLAB的 \extern\lib\win32\microsoft 路径。
    连接器 -> 输入 -> 附加依赖项 输入libmx.lib libeng.lib libmat.lib libmex.lib 这四个lib文件。
    b. 编辑输出函数
    在项目源文件的. def 中EXPORTS段加入 mexFunction, 如:
    EXPORTS
        ; 此处可以是显式导出
        mexFunction
    c. 编写MEX文件
    项目文件中新建一个C++文件 如 mexproc.cpp,里面按前面介绍的格式编写代码即可。
    d. VC编译MEX
    像编译其他程序那样直接编译即可,成功会生成dll文件。如果编译链接时出错,根据错误提示,检查一下lib和h的路径是否正确,有无缺少lib文件,代码是否有语法错误等。
    3. VC中调试MEX
    要调试MEX程序就要先编译,再调用她。所以我们需要在MATLAB中调用这个函数,并在VC的MEX程序相应位置处下断点即可。调用的函数名就是dll的主文件名,你可以根据自己的需要改名。我们用mymexfun.dll为例,先在VC的 mexFunction 函数代码段开始处F9下断。然后Ctrl+Alt+P附加MATLAB.exe进程。这样就可以运行命令调试程序了。我们可以在MATLAB的命令行里输入命令:
              [输出变量] = mymexfun(输入变量)
    (如果命令找不到,检查一下matlab当前路径,和path路径。)
    程序一旦被调用,就会被断在我们的断点处。接着你就可以像调试C++程序那样调试MEX程序了。
    在MATLAB中编译MEX可以输入: mex 文件名.cpp
    MATLAB上编译MEX时,你可以选择不同的编译器如lc, gcc等。也可以在编译时附加lib和h文件。关于mex的命令详解请参考MATLAB帮助文档。
    多多发帖,受益多多
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 注册地址

    qq
    收缩
    • 电话咨询

    • 04714969085
    fastpost

    关于我们| 联系我们| 诚征英才| 对外合作| 产品服务| QQ

    手机版|Archiver| |繁體中文 手机客户端  

    蒙公网安备 15010502000194号

    Powered by Discuz! X2.5   © 2001-2013 数学建模网-数学中国 ( 蒙ICP备14002410号-3 蒙BBS备-0002号 )     论坛法律顾问:王兆丰

    GMT+8, 2025-5-17 12:12 , Processed in 0.598756 second(s), 72 queries .

    回顶部