12 MATLAB编译器和API
几乎所有使用过MATLAB的科技人员,无不为该软件的简洁、便捷和功能之强大和可靠所震撼,同时也对MATLAB产生了新的期望:一,希望程序能运行得更快;二,希望获得可摆脱MATLAB环境而运行的可执行软件;三,希望从其他“非MATLAB”的外部程序中调用MATLAB。
本章前6节介绍MATLAB版编译器(Compiler)。由于1.2版与2.0版差异较大,又由于2.0版缺少1.2版具有的优化功能,因此内容安排上将兼顾地论及两个版本。值得指出的是:除Mathworks外,还有其他一些公司生产的编译器,其中比较著名的是MathTools公司的Mediva;据该公司自称,性能优于Mathworks的,且具有绘图功能。
本章第7节论及API应用程序接口,扼要地介绍不同平台间的数据传送和MATLAB引擎技术。节后算例演示了,如何从外部调用MATLAB引擎。
12.1编译器2.0概述
12.1.1编译器2.0的功能
12.1.3编译器2.0 的局限性12.1.2编译器2.0的性能改进
[circle.m]
clf;r=2;t=0:pi/100:2*pi;x=r*exp(i*t);
plot(x,'r*');axis('square')
(2)对这脚本文件直接编译将因错误而失败
mcc-x circle
???Error: File "circle" is a Script M-file and cannot becompiled with the current Compiler.
Errorin ==> H:\MATLAB53\toolbox\compiler\mcc.dll
(3)把脚本文件改写成函数文件。
[circle_f.m]:
functioncircle_f(r)
clf;t=0:pi/100:2*pi;x=r*exp(i*t);
plot(x,'r*');axis('square')
(4)再对circle_f.m 进行编译,将顺利通过。
mcc -x circle_f | %mcc 是编译指令,详见12.4 节。 |
|
(5)运行生成的MEX文件circle_f.dll
circle_f(0.5) %调用circle_f绘制一半径为0.5的圆
whichcircle_f %查询所调用的circle_f的路径全称。
d:\mywork\circle_f.dll
?5
?4
?3
?2
?1
?
??
??
??
??
?? ?? | ? | ?5 |
图12.1.4-1 MEX文件circle_f.dll所画的圆
12.2编译器的安装和配置
12.2.1配置MATLAB 编译器的前提准备
图12.2.1-1 【SelectMATLAB Componets】对话窗的选项局部图
12.2.2为产生MEX文件进行预配置
12.2.2.1 对MATLAB编译器应用程序mex的设置
图12.2.2.1-1 为产生MEX文件所产生的配置屏1
图 12.2.2.1-2 为产生MEX 文件所产生的配置屏2 12.2.2.2 配置正确性的验证
(1)mex 应用程序的验证
cdd:\mywork %把用户目录指定为当前目录
mexmy_yprime.c %由my_yprime.c文件生成my_yprime.dll文件
my_yprime(1,1:4)%运行my_yprime.dll文件
whichmy_yprime %获得my_yprime.dll文件的位置信息
ans=
2.0000 8.9685 4.0000 -1.0947
d:\mywork\my_yprime.dll
(2)在MATLAB命令窗中验证mcc应用程序
mcc -x my_yprime_m | %<1> |
(3)在DOS提示符后验证mex、mcc应用程序
图 12.2.2.2-1 在DOS状态下验证编译指令
12.2.3.1
图 12.2.3.1-1 为产生外部应用程序所产生的配置屏1
12.2.3.2 对MATLAB 编译器mbuild应用程序的设置(1.2 版) 图12.2.3.1-2 为产生外部应用程序所产生的配置屏2
12.2.3.3
cd d:\mywork %把用户目录指定为当前目录
mbuildmy_ex1.c %在d:\mywork下生成my_ex1.exe文件
图12.2.3.2-1 在DOS窗口运行验证程序my_ex1.exe所得的结果
(2)mcc应用程序的验证
mcc-p my_hello.m %<1>
图12.2.3.2-2 在DOS窗口运行验证程序my_hello.exe所得的结果
(3)在DOS状态下验证mbuild、mcc工作正确性
图 12.2.3.2-3 在DOS状态验证编译指令
12.3.1由M 文件创建CMEX 文件的入门算例
【例12.3.1-1】先编写M文件,然后生成相应的MEX文件。该文件用以判断方阵是否奇异。
cdd:\mywork
(1)在MATLAB的编辑器中,编写下面的函数文件exm1.m。
[exm1.m]
function y=exm1(A)
[m,n]=size(A);
if m~=n;
error('An input matrix should be n-by-n.')
end
r=rank(A);
if r==m
disp('This matrix isnonsigular')
else
disp('This matrix is sigular')
end
(2)把该函数文件存放于用户目录d:\mywork下。
(3)在MATLAB命令窗中,运行以下指令对exm1.m进行编译。
mcc-x exm1 %编译m文件。
(4)调用MEX文件exm1.dll进行计算
A=[1,0,1;2,1,0;4,1,4]
exm1(A) %调用exm1来判断矩阵A是否奇异。whichexm1 %查询所调用的exm1的路径和全称。
A=
1 0 1
2 1 0
4 1 4
Thismatrix is nonsigular
d:\mywork\exm1.dll
12.3.2由M文件创建外部应用程序的入门算例
【例12.3.2-1】建立一个脱离MATLAB环境,可运行的外部程序。该程序的功能是:对于给定矩阵A,如果存在S使得S-1AS=Λ,则要求出一个S,否则给出信息说明所给的矩阵A不能对角化。
(1)编写两个M函数文件:exm2.m和exm2_f.m。(第一个文件是主文件。)[exm2.m]
functionexm2
A=[4,0,0;0,3,1;0,1,3];
S=exm2_f(A)
function S=exm2_f(A) [m,n]=size(A); if m~=n[exm2_f.m]
e=eig(A);
same=0; end;
fori=1:m-1
forj=(i+1):m
ife(j)==e(i)
same=1;
end
end
end
%A可以对角化的条件是A具有互异特征值或者A为埃尔米特矩阵。
ifany(any((A'-A)))&(same==1)
error('矩阵无法对角化!');
end
[v,d]=eig(A);
S=v;
(2)把这两个函数文件存放于用户自己的目录d:\mywork,并在MATLAB中运行检验。
exm2
S =
1.0000 0 0 0 0.7071 0.7071 0 0.7071 -0.7071
(3)生成的外部可执行程序。在MATLAB指令窗中,运行如下指令mcc-m exm2 exm2_f
(4)打开DOS窗口,在d:\mywork目录下,运行exm2.exe,得如图12.3.2-1的结果。
图12.3.2-1 在DOS窗口运行生成程序exm2.exe所得的结果
12.4编译指令mcc简介
12.4.1mcc的基本调用格式
12.4.2 mcc 的选项标志
12.4.2.2
【例12.4.2.2-1】假设当前目录上存在一个文件exm3.m,现要求利用M编译器将它转换为C++
12.4.2.1
语言的源码文件,并要求将原M文件中那注释区的内容作为所得C++源码文件的注释。
mcc -t -L Cpp -A annotation:comments exm3 12.4.2.3 设置缺省选项
%得到exm3.cpp和exm3.hpp
【例12.4.2.3-1】假设已在d:\mywork 下创建了文本文件mccstartup (请注意:该文件不可带
扩展名),该文件的内容包括若干编译指令的选项。现要求利用该文件,从exm3.m 出发得
到C++语言的源文件。
cd d:\mywork
type mccstartup
-t -L C -A annotation:none
!copy mccstartup h:\y9857\temp !copy exm3.m h:\y9857\temp
%将d:\mywork设为当前工作目录%打印文本文件mccstartup的内容
%将mccstartup转移到临时目录下%将待编译M源码转移到临时目录下
!del mccstartup , %删除mccstartup
!del exm3* %删除原有的编译后文件
dir mccstartup
dir h:\matlab53\bin\mccstartup
dir exm3*
1 file(s) copied 1 file(s) copied mccstartup not found.
%当前目录下是否含有mccstartup%<matlab>\bin 下是否含该文件
%当前目录下是否含有exm3*
h:\matlab53\bin\mccstartupnot found.
exm3*not found.
!copyh:\y9857\temp\exm3.m d:\mywork
mcc -L Cpp exm3 %<1> 1 file(s) copied
???Error: The options specified will not generate any output files.Please use one of the following options to generate an executableoutput file:
-x (generates a MEX-file executable using C)
-m (generates a stand-alone executable using C)
-p (generates a stand-alone executable using C++)
-S (generates a Simulink MEX S-function using C)
Ortype mcc -? for more usage information.
Errorin ==> H:\MATLAB53\toolbox\compiler\mcc.dll
!copy h:\y9857\temp\mccstartup d:\mywork mcc -L Cpp exm3
dir exm3*
!del mccstartup
1 file(s) copied
exm3.cpp exm3.hpp exm3.m
12.4.2.4 编译器1.2 选项简介
%将mccstartup拷贝到当前目录%<2>
%<3>
【例12.4.2.4-1】要求利用1.2 版编辑器对文件exm4.m 进行操作,目标是获得C MEX 文件
(1)在5.3 版MATLAB 指令窗中的执行指令mcc -V1.2 exm4和C 语言的可执行文件。
mcc -V1.2 -em exm4
mcc exm4 mcc -em exm4
12.5编译文件的性能优化
12.5.1优化原M 文件的性能
12.5.1.1 提高向量化程度
【例12.5.1.1-1】本例演示:M 文件与MEX 文件、向量运算与循环运算的速度比较。(1)编写如下两类函数M 文件。
function y=sa(x)
x=x+(x==0)*eps;
y=sin(x)./x;
function y=saf(x)
n=length(x);
for k=1:n
end | x(k)=x(k)+(x(k)==0)*eps; |
|
y(k)=sin(x(k))/x(k); | ||
|
(2)在MATLAB指令窗中,对sa_mex.m和saf_mex.m进行编译。
cd d:\mywork | %<1> |
(3)运行四个文件,记录运算时间
t=-2*pi:pi/500:2*pi;
tic;sa(t);tt(1)=toc;
tic;saf(t);tt(2)=toc;
tic;sa_mex(t);tt(3)=toc;
tic;y=saf_mex(t);tt(4)=toc;
(4)结果显示和比较
plot(t,y,'r-');grid
?
?8
?6
?4
?2
?
??
disp('运算速度比较') ??
??
运算速度比较 disp(tt)
12.5.1.2 对数组进行预置
【例12.5.1.2-1】以上节例12.5.1.1-1为基础。saf.m文件中数组变量x和y的大小随循环进
行而增长,这大大减慢了运算速度。本例演示:在循环前对进行变量预置的好处。
(1)编写如下文件,以saf_pro.m和saf_pro_mex.m为名,将之保存在当前目录下。
functiony=saf(x)
n=length(x);
x=zeros(1,n);y=zeros(1,n);
fork=1:n
x(k)=x(k)+(x(k)==0)*eps;
y(k)=sin(x(k))/x(k);
end
(2)产生编译文件
mcc -x saf_mex
mcc -x saf_pro_mex
(3)运行 |
|
tic;saf(t);tt(1)=toc;
tic;saf_pro(t);tt(2)=toc;
tic;saf_mex(t);tt(3)=toc;
tic;y=saf_pro_mex(t);tt(4)=toc;
(4)速度比较
disp('运算速度比较')
disp(' saf.m saf_pro.m saf_mex.dll saf_pro_mex.dll')
disp(tt)
运算速度比较
saf.m saf_pro.m saf_mex.dll saf_pro_mex.dll
2.8600 0.6600 2.6300 0.4400
12.5.1.3 避免调用复数域函数
12.5.2利用mcc(-V1.2)的优化性能
12.5.2.1 编译时指定优化选项-r和-i
【例12.5.2.1-1】求如下非线性差分方程组在10000个点上的值。观察原M文件、无选项和
有选项MEX文件运行速度的不同。
?
?
xk?1?1?yk?1. 4 xk 2
x0?0, y0?0
?yk?1?0. 3 xk
x=zeros(1,n);y=zeros(1,n);
for k=1:n-1(1)利用MATLAB编辑窗口编写如下M 函数文件
function[x,y]=m_henon(n)
end
cdd:\mywork
mcc-x mex20_henon %用2.0编译器产生普通MEX文件<1>
mcc-V1.2 -ri ri_mex12_henon %用1.2编辑器产生优化的MEX文件<2>
(3)计算各文件运行时间费用的相对值。
n=10000;
t=zeros(3,2);
for k=1:2
tic;m_henon(n);t(1,k)=toc;
tic;mex20_henon(n);t(2,k)=toc; tic;ri_mex12_henon(n);t(3,k)=toc; end
t=t/t(1,1);
(4)显示比较结果
filename=[ ' m_henon';
' mex20_henon'; 'ri_mex12_henon';];
%运行两次,以做比较
disp([' 各文件运行开销的相对值比较表']) |
| |
disp(blanks(1)') | %产生一个空行 | |
disp([' 文件名第一次运行第二次运行']) disp([filename blanks(3)' blanks(3)' num2str(t)]) %blanks 产生两个空列 | ||
各文件运行开销的相对值比较表
文件名第一次运行第二次运行
m_henon 1 0.78086
mex20_henon 0.69753 0.59259
ri_mex12_henon 0.015432 0
12.5.2.2 利用变量类型申明优化性能
12.5.2.3 利用编译注记优化性能
【例12.5.2.3-1】编译注记%#ivdep的应用举例。
(1)编写如下两个函数M文件,并存放在d:\mywork目录上。
[ivdep0.m]
functionA=ivdep0()
A=1:10;
A(5:9)=A(3:7);
[ivdep.m]
functionA=ivdep()
A=1:10;
A(5:9)=A(3:7);
(2)分别对这两个文件进行编译。%#ivdep
cd d:\mywork
tic;A0=ivdep0;t0=toc;
tic;A=ivdep;t=toc/t0;
(4)显示结果。
A0,A
disp(['使用编译注记%#ivdep后的运用时间仅为原来的 'num2str(t)]) A0=
1 2 3 4 3 4 5 6 7 10 A =
1 2 3 4 3 4 3 4 3 10
使用编译注记%#ivdep后的运用时间仅为原来的 0.15152
12.6创建的外部应用程序
12.6.1外部程序的工作特点和创建过程
12.6.1.1 外部程序与MEX文件的不同工作特点
12.6.1.2 外部程序创建过程说明
12.6.2关于指令mbuild
12.6.3借助编译指令mcc创建应用程序
12.6.3.1 创建应用程序时mcc的使用格式和常用选项标志
12.6.3.2 由全M源文件产生EXE应用程序
【例12.6.3.2-1】创建一个适应“超定”、“恰定”、“欠定”线性方程求解的示例性应用程序。
(1)编写以下两个M函数文件。
[LLS.m]
functionLLS()
Ae=5;%<2>%<3> Av=2;
[A,b]=LLSDATA(Ae,Av);
x=A\b;
%以下都是为获得较清晰的显示而编写
if Ae>Av S='超定';S='恰定';
end
cs=blanks(Ae)'; elseif Ae<Av
ns=fix(Ae/2); %从零方向最接近空白列长之半的数
As=cs;As(ns)='A';
bs=cs;bs(ns)='b';
es=cs;es(ns)='=';
disp([Ascs es cs num2str(A) cs cs cs cs cs bs cs es cs num2str(b)])disp('方程的解')
nxs=fix(Av/2);
cxs=blanks(Av)';
xs=cxs;xs(nxs)='x';
exs=cxs;exs(nxs)='=';
disp([xscxs exs cxs num2str(x)])
[LLSDATA.m]
function[A,b]=LLSDATA(Ae,Av)
n=max(Ae,Av);
WA=magic(n);
A=WA(:,1:Av);
if n>Ae
A=WA(1:Ae,:);
end
b=ones(Ae,1);
(2)对存放在d:\mywork上的这两个文件进行编译。
图12.6.3.2-1 应用程序LLS.exe解超定方程示例
(3)把LLS.m文件第2、3行改为Ae=3;Av=5,重新编译、运行,结果见图12.6.3.2-2。
图12.6.3.2-2 应用程序LLS.exe解欠定方程示例
12.6.3.3 由含feval指令的M文件生成EXE文件
【例12.6.3.3-1】采用编译指定法生成一个可以计算方阵各种特征量的外部应用程序。(1)编写函数M文件:mat_feat.m和my_det.m。
[mat_feat.m]
function mat_feat(f_name) | %给定的被分析矩阵 | %<1> |
disp('被分析矩阵') | %<2> | |
A=magic(4) | ||
N=8; | %为字符串比较而设的字符串长度 8 。 |
n=size(f_name,2);
ff_name=[f_name blanks(N-n)];
%测量输入字符串的长度%给输入字符串补充空字符,使长度为8。
if ff_name==['my_det' blanks(2)] disp('矩阵 A 的行列式值 = ') |
|
elseifff_name==['rank'blanks(4)]
disp('矩阵A的秩=')
elseifff_name==['norm'blanks(4)]
disp('矩阵A的2-范数=')
elseifff_name==['cond'blanks(4)]
disp('矩阵A的条件数=')
elseifff_name==['eig'blanks(5)]
disp('矩阵A的特征值=')
elseifff_name==['svd'blanks(5)]
disp('矩阵A的奇异值=')
else
disp('您输入的指令,或者不是本函数文件所能解决的,或是错误的!')end
d=feval(f_name,A);
disp(d)
[my_det.m]
functiond=my_det(A)
d=det(A);
(2)创建计算给定矩阵秩的EXE文件
mcc-V1.2 -pm mat_feat f_name=rank
!mat_feat WARNING: Reference to uninitialized variable被分析矩阵(3)所生成的mat_feat.exe可脱离MATLAB 而运行。
矩阵 A 的秩=
(4)求矩阵行列式值的EXE文件创建指令、验证运行指令、及运行结果。mcc-V1.2–p –m mat_feat f_name=my_det
!mat_feat
被分析矩阵
[ 16 2 3 13 ;
5 11 10 8 ;
9 7 6 12 ;
4 14 15 1 ]
矩阵A的行列式值=
0
【例12.6.3.3-2】采用编译注记法生成一个可以计算方阵行列式值的外部应用程序。(1)假定想创建一个计算矩阵行列式值的应用程序,那么只要在上例mat_feat.m文件的第<1>和<2>行之间插入以下两行指令,而M文件的其余部分都不必改动。
%#function my_det
f_name='my_det';
(2)用以下指令对M 文件进行编译,便可得到正确的EXE 文件。
mcc–p mat_feat
【例12.6.3.3-3】当feval调用的是MATLAB C++库中的函数时,可以采用更简单的feval输
入宗量直接赋值法,实现EXE文件的创建。如创建一个计算方阵特征值的外部应用程
序。
(1)只要在例12.6.3.3-1的mat_feat.m文件第<1>和<2>行中间插入如下一条指令即可。
f_name='eig';
(2)用以下指令对M文件进行编译,便可得到正确的EXE文件。mcc–p mat_feat
(3)以下是运行指令和结果
!mat_feat
被分析矩阵
A=
16 2 3 13
5 11 10 8
9 7 6 12
4 14 15 1
矩阵 A 的特征值 = | ||||||||
8.9443 |
| |||||||
12.6.3.4 | ||||||||
(1)为了让读者了解函数 | y ? | 1 | sin( | xe | 0 . 6 | x | ) | ,对将生成的EXE 文件的运行结果正确性做直 |
| x | | | | | | | |
观的判断。先运行以下指令绘制如图12.6.3.4-1所示的函数曲线。xx=0:0.01:5;
yy=SAA(xx); %SAA.m文件见本例第2步
plot(xx,yy)
x0=2;
x=fmins('SAA',x0);
y=SAA(x);
plot(xx,yy,'b-',x,y,'r.','MarkerSize',20),grid
??
??
?
?и
??
??
??
?
??
??
?? | 0 | 1 | y ? | 1 | 2 | xe | 3 | ) | 4 | 5 | |
图12.6.3.4-1函数 | sin( | 0 . 6 | x | 在2 附近的局部最小值 | |||||||
| x | | | | | | |||||
(2)编制以下M函数文件,并存放在用户自己的工作目录上。
[fcpp.m]
functionfcpp(fun)
%#functionSAA %被泛函调用函数的编译注记是必须的。
fun='SAA'; %对泛函指令中第一输入宗量具体化也是必须的。
xs=1;
x=fmins(fun,xs);
disp(blanks(2)')
disp('外部程序 fcpp.exe运行结果显示')y=feval(fun,x);
disp(blanks(2)')
disp(ss);
disp(['
[SAA.m]
functiony=SAA(x)
x=x+(x==0)*eps;
y=sin(x.*exp(0.6*x))./x;
(3)在MATLAB指令窗或DOS环境中运行以下编译指令,在用户目录上产生
fcpp.exe。
mcc–p fcpp
(4)在DOS中运行fcpp.exe的操作情况和结果如图12.6.3.4-2。
图12.6.3.4-2生成的程序fcpp.exe在DOS中的运行结果
12.6.3.5 由C/C++源码和M源码文件混合生成EXE应用文件
【例12.6.3.5-1】主程序为C源码文件,被调用程序为M文件。
(1)主文件fileinc.c和被调用的mrank.m文件如下
[fileinc.c]
#include<stdio.h>
#include"matlab.h"
#include"templib.h"
int main(int argc, char **argv[]) { int n ;
*mxGetPr(N)=n;
r = mlfMrank(N);
mlfPrintMatrix(r);
mxDestroyArray(r);
mxDestroyArray(N);
TemplibTerminate();
return 0;
}
[mrank.m]
functionr=mrank(n)
r=zeros(n,1);
fork=1:n
r(k)=rank(magic(k));
end
(2)编译混合源码文件
mcc–t –W lib:Templib -T link:exe mrank fileinc.c
mcc –t –W lib:Templib -T link:exe fileinc.c mrank
(3)在DOS中分别运行mrank.exe和fileinc.exe 的结果如图12.6.3.5-1。
图12.6.3.5-1 混合源码产生的mrank.exe和fileinc.exe运行结果
12.7API应用程序接口
12.7.2数据的输入输出12.7.1MEX 文件
12.7.2.2 12.7.2.1
12.7.2.3 不同平台间数据传递
12.7.3MATLAB引擎
【例17.7.3-1 】在C 源程序中调用MATLAB 引擎来计算三次多项式 | x | 3 | ?x | ? | 5 | 的根。 |
(1)编写源程序engexam.c。
#include<windows.h>
#include<stdlib.h>
#include<stdio.h>
#include"engine.h"
intPASCAL WinMain (HANDLE hInstance,
HANDLE hPrevInstance,
LPSTR lpszCmdLine,
int nCmdShow)
{ | Engine *ep; |
|
mxArray *P=NULL,*r=NULL; |
char buffer[301];
double poly[4]={1,0,-2,5}; /*三次多项式的系数*/
/*启动本机MATLAB引擎,如果出错则退出程序。
如想启动远程主机上的MATLAB,则用相应主机名代替\0*/if (!(ep=engOpen("\0"))) {
fprintf(stderr,"\nCan'tstart MATLAB engine\n"); returnEXIT_FAILURE;}
/*创建变量P,将poly变量中定义的多项式系数值拷贝至该变量P*/
P=mxCreateDoubleMatrix(1,4,mxREAL);
/*给变量P取名为p,将P传递到引擎空间,p将被运用于MATLAB表达式中*/mxSetName(P,"p");
memcpy((char*)mxGetPr(P),(char *)poly,4*sizeof(double));
engPutArray(ep,P);
/*利用MATLAB求解多项式根,并写至缓冲区*/
engOutputBuffer(ep,buffer,300);
engEvalString(ep,"r=roots(p)");
/*将缓冲区中的内容输出屏幕窗口,关闭MATLAB引擎,释放指针P。*/MessageBox(NULL,buffer,"Engexam.c--多项式x^3-2x+5的根",MB_OK);engClose(ep);
mxDestroyArray(P);
} | return EXIT_SUCCESS; |
|
| ||
图12.7.3-1 运行程序engexam.exe得到的信息窗口
Copyright © 2019- tjwe.cn 版权所有
违法及侵权请联系:TEL:199 18 7713 E-MAIL:2724546146@qq.com
本站由北京市万商天勤律师事务所王兴未律师提供法律服务