chinandy的个人博客分享 http://blog.sciencenet.cn/u/chinandy

博文

如何在64位Matlab中调用C/C++处理大容量数据(largeArrayDims)

已有 12724 次阅读 2013-1-17 20:11 |个人分类:MATLAB|系统分类:科研笔记| 兼容性, largeArrayDims

随着计算机软硬件水平的不断提升,64位操作系统逐步开始普及,作为数值计算领域著名的数学计算工具,Matlab也在逐步提高自身的兼容性。另一方面,作为软件编程领域的重要语言,C或者C++在运行性能上有着明显的优势,因此在Matlab中调用C++和C成了聪明的人在实际运行中的通常做法。
Matlab调用C或者C++其实不难,其核心是对于一些mexFunction的理解,这也不是本问关注的内容。这里,笔者只是想讨论如何把32位系统下编译的C或者C++程序移植到64位系统中,首先请看一个例子。
假设我们要快速生成一个给定大小的Hilbert矩阵,要求用C或者C++写,然后在matlab中调用。因此,可以写出该算法的C代码如下:

/*

Create the n*n Hilbert Matrix

*/

 

# include "mex.h"

 

void hilb(double *y,int n)

{

    int i,j;

    for(i=0;i<n;i++)

        for(j=0;j<n;j++)

            *(y+j+i*n)=1/((double)i+(double)j+1);

}

 

void mexFunction(int nlhs,mxArray *plhs[],int nrhs,const mxArray *prhs[])

{

         //x is the input param,y is the pointer to the matrix create in c

    double x,*y;

 

         //the size of the matrix

    int n;

 

         //only one param for input is allowed

    if (nrhs!=1)

        mexErrMsgTxt("One inputs required.");

 

         //only one param for output is allowed

    if (nlhs != 1)

        mexErrMsgTxt("One output required.");

 

         //the param inout must be a scaler which type is double

    if (!mxIsDouble(prhs[0])||mxGetN(prhs[0])*mxGetM(prhs[0])!=1)

        mexErrMsgTxt("Input must be scalars.");

 

         //get the size of matrix we want  to create

    x=mxGetScalar(prhs[0]);

 

         //create a x*x matrix,the element's datatype is real double,

         //and the matrix's pointer is associated with the firt output param.

    plhs[0]=mxCreateDoubleMatrix(x,x,mxREAL);

 

         //get the row numbers of the created matrix

    n=mxGetM(plhs[0]);

 

         //get the pointer of the created matrix

    y=mxGetPr(plhs[0]);

 

         //call subfunction

    hilb(y,n);

}

 

    以上内容命名为hilbertc.c文件,然后保存到matlab的当前目录下,运行指令
>>mex hilbertc.c
    在同路径下会生成该函数的mex文件hilbertc.mexw32,然后我们在matlab中调用这个函数,代码如下:
>> A=hilbertc(10)

A =

    1.0000    0.5000    0.3333    0.2500    0.2000    0.1667    0.1429    0.1250    0.1111    0.1000
    0.5000    0.3333    0.2500    0.2000    0.1667    0.1429    0.1250    0.1111    0.1000    0.0909
    0.3333    0.2500    0.2000    0.1667    0.1429    0.1250    0.1111    0.1000    0.0909    0.0833
    0.2500    0.2000    0.1667    0.1429    0.1250    0.1111    0.1000    0.0909    0.0833    0.0769
    0.2000    0.1667    0.1429    0.1250    0.1111    0.1000    0.0909    0.0833    0.0769    0.0714
    0.1667    0.1429    0.1250    0.1111    0.1000    0.0909    0.0833    0.0769    0.0714    0.0667
    0.1429    0.1250    0.1111    0.1000    0.0909    0.0833    0.0769    0.0714    0.0667    0.0625
    0.1250    0.1111    0.1000    0.0909    0.0833    0.0769    0.0714    0.0667    0.0625    0.0588
    0.1111    0.1000    0.0909    0.0833    0.0769    0.0714    0.0667    0.0625    0.0588    0.0556
    0.1000    0.0909    0.0833    0.0769    0.0714    0.0667    0.0625    0.0588    0.0556    0.0526

    程序执行成功。以上全部是基于32位的matlab.如果把上述程序放在64位版本的matlab下运行,结果会怎么样呢?64位的matlab能兼容32位matlab所编译出的mex程序吗?
实践是回答问题的最好方法,现在我们把hilbertc.mexw32拷贝到64位Matlab的机器下,执行以下代码:
>>  A=hilbertc(10)
Undefined function 'hilbertc' for input arguments of type 'double'.
    结果是执行出错,其原因是由于32位字长下double类型与64位下double在内存中所占的字节数不同,导致系统在参数传递时发生匹配错误。对于这个问题,我们很好解决,只要在64位平台下重新编译C或者C++源代码文件即可。代码如下
>> mex hilbertc.c
>> A=hilbertc(10)

A =

    1.0000    0.5000    0.3333    0.2500    0.2000    0.1667    0.1429    0.1250    0.1111    0.1000
    0.5000    0.3333    0.2500    0.2000    0.1667    0.1429    0.1250    0.1111    0.1000    0.0909
    0.3333    0.2500    0.2000    0.1667    0.1429    0.1250    0.1111    0.1000    0.0909    0.0833
    0.2500    0.2000    0.1667    0.1429    0.1250    0.1111    0.1000    0.0909    0.0833    0.0769
    0.2000    0.1667    0.1429    0.1250    0.1111    0.1000    0.0909    0.0833    0.0769    0.0714
    0.1667    0.1429    0.1250    0.1111    0.1000    0.0909    0.0833    0.0769    0.0714    0.0667
    0.1429    0.1250    0.1111    0.1000    0.0909    0.0833    0.0769    0.0714    0.0667    0.0625
    0.1250    0.1111    0.1000    0.0909    0.0833    0.0769    0.0714    0.0667    0.0625    0.0588
    0.1111    0.1000    0.0909    0.0833    0.0769    0.0714    0.0667    0.0625    0.0588    0.0556
    0.1000    0.0909    0.0833    0.0769    0.0714    0.0667    0.0625    0.0588    0.0556    0.0526
    问题如果只进行到这里,那就太肤浅了,我今天的目地在于介绍一种充分利用64位matlab的精度和容量优势,提高其运算量的方法。
众所周知,能安装64位matlab的机器一般配置都是比较高的,特别是内存容量比较大,比较适合处理大容量数据。上述问题的解决方法,只是让64位系统以一种兼容模式运行32位C程序,其本质是以好兼容性牺牲性能。下面介绍一种在保证兼容性的条件下,充分发挥matlab处理大容量数据的方法。总结一下,可以表述为如下问题:
    How do I update MEX-files to use the large array handling API (-largeArrayDims)?
    如何更改Mex文件以使用处理大容量数组的API?
    由于传统的C或者C++语言历史久远,其盛行与16位系统与32位系统期间,当计算机进入64位时,软件支持仍以32位时的标准为模版,这就是为什么我们的入口函数通常是以int作为数组下标和元素个数的索引的原因。在32位系统中,int占4个字节,最多能表示2^32-1个数,可是随着时代的发展,人们处理的问题越来越复杂,处理的数据量越来越大。2^32-1个数肯定在某些行业已经不够用了,然而matlab与C++之间的接口是以32位系统作为标准的,这就导致了人们在处理大容量数据时没办法利用C和C++语言的速度优势,而往往对于大数据量来说,运算速度是很关键的。
    因此,如何更改接口使得matlab与C++之间的接口能处理大容量数据,成为了迫切需要解决的问题。
    对于这个问题,其解决方案如下:
    1.检查自己的代码,将那些指代矩阵索引的下标整数的类型改为 mwSize 或者mwIndex,在matlab的头文件中,已经将 mwSize 和mwIndex重定义为了size_t 类型,而C++中size_t是64位的,这就保证了我们的接口是基于64位的,从而就可以处理 大容量数据了。
    2.第一步骤只是给了我们表示和索引大数据量的能力,如何处理这些大数据量还需要进行第二部。在matlab和C++之间的接口函数是基于众多mex函数和mx函数组成的API函数集,要使用这些函数集对我们的大容量数据进行处理,我们必须保证传递到这些函数中的参数必须是大容量的。因此这一步骤,我们主要寻找那些调用mx*和mex*开头的函数,然后查看其传入函数,如果函数院校为int,则将int改为 mwSize 或者mwIndex。
    matlab的接口头文件中,定义的以下函数可以对大容量数组进行处理:
mxCalcSingleSubscriptmxCreateSparseLogicalMatrix2
mxCallocmxCreateStructArray
mxCopyCharacterToPtr1mxCreateStructMatrix
mxCopyComplex16ToPtr1mxGetCell
mxCopyComplex8ToPtr1mxGetDimensions
mxCopyInteger1ToPtr1mxGetElementSize
mxCopyInteger2ToPtr1mxGetField
mxCopyInteger4ToPtr1mxGetFieldByNumber
mxCopyPtrToCharacter1mxGetIr
mxCopyPtrToComplex161mxGetJc
mxCopyPtrToComplex81mxGetM
mxCopyPtrToInteger11mxGetN
mxCopyPtrToInteger21mxGetNumberOfDimensions
mxCopyPtrToInteger41mxGetNumberOfElements
mxCopyPtrToPtrArray1mxGetNzmax
mxCopyPtrToReal41mxGetProperty
mxCopyPtrToReal81mxGetString
mxCopyReal4ToPtr1mxMalloc
mxCopyReal8ToPtr1mxRealloc
mxCreateCellArraymxSetCell
mxCreateCellMatrixmxSetDimensions
mxCreateCharArraymxSetField
mxCreateCharMatrixFromStringsmxSetFieldByNumber
mxCreateDoubleMatrixmxSetIr
mxCreateLogicalArray2mxSetJc
mxCreateLogicalMatrix2mxSetM
mxCreateNumericArraymxSetN
mxCreateNumericMatrixmxSetNzmax
mxCreateSparsemxSetProperty
上标1表示只对Fortan语言有效。
上标2表示只对C语言有效

    按照以上思路,对C或者C++源代码进行更改后,就可以编译了。编译时和常规编译不同,需要附件大容量编译的参数。具体如下:
>>mex -largeArrayDims  hilbertc .c
    这样生成的mex程序文件就可以支持大容量的数组和矩阵,并能在程序中对这些数据和矩阵进行处理了。



https://blog.sciencenet.cn/blog-810210-654128.html

上一篇:Orthogonal Matching Pursuit(OMP)正交匹配追踪算法学习笔记
下一篇:矩阵按列按行归一化到L2范数的原理和最精简Matlab代码
收藏 IP: 222.190.117.*| 热度|

4 王浩 梁大成 许海云 Jasion

该博文允许注册用户评论 请点击登录 评论 (0 个评论)

数据加载中...

Archiver|手机版|科学网 ( 京ICP备07017567号-12 )

GMT+8, 2024-11-24 01:55

Powered by ScienceNet.cn

Copyright © 2007- 中国科学报社

返回顶部