Matlab与VC混合编程之三

Matlab与VC混合编程之三

1. 有没有优雅的使用方式?

在《Matlab与VC混合编程之二》中我们学会了如何使用向量或者矩阵在VC与Matlab COM组件之间传递参数。在第二章的实现中,标量和向量的使用方式勉强可以接受,矩阵的使用方式简直令人发狂。而我们的大多数科学计算或者工程计算都需要用到矩阵,如何改进对矩阵(二维数组)的访问方式,是本章要回答的问题。在本章中,我们使用用C++的类来封装这种复杂性,把标量和向量作为矩阵的特殊情况,使用类来表达矩阵的概念。经过封装之后,以后再使用时就直接调用类的接口,实现了简单优雅访问Matlab生产的COM组件。首先讲解一些C++的类基本概念,之后讲解矩阵了matrix的实现方式,最后在附录中给出完整的源代码。

2. 基本概念

a.需要几个类来封装

使用类来表示概念和针对接口编程,是设计一个良好的类需要遵循的原则。在VC与Matlab COM的访问中,我们需要“矩阵”这一概念。使用Matlab时会注意到matlab的几乎所有函数的输入输出参数都是矩阵,向量和标量只是矩阵的特殊形式,向量是只有一行(行向量)或者只有一列(列向量)的矩阵,标量是只有一行一列的矩阵。理解了这一点之后,我们就只需要一个概念,即矩阵。所以我们只需要实现或者定义一个类matrix。

b.类的接口有哪些

类的接口指类的共有方法(public函数)。类的接口有哪些,是由使用该类的客户的上下文(环境)来确定的。也就是说在定义类的接口时要站在客户(使用类的人或者代码)的角度去考虑问题。在这里,使用matrix时,我们需要能够将数据赋值到matrix中,能够将matrix作为输入参数传递给Matlab COM的接口函数去完成计算,能够将matrix作为输出参数传递给Matlab COM的接口函数从而获得计算的结果,能够将matrix中的数据获取出来。

如图1所示。

Matlab与VC混合编程之三

图1 matrix封装示意图

写成伪代码的形式如下:

double dx[2][2] = {1,2,3,4}; //客户需要计算的数据

matrix mx, my; //matrix变量的定义

mx.setMatrix(2,2,dx);//将客户数据赋值到matrix中

long varNum = 1;

pInterface->calcSin(varNum, &my, mx); //matrix作为输入参数和输出参数,假定这里的COM函数是求正弦值

double dy[2][2] = {0}; //客户需要获取结果数据

my.getData(dy);  //将matrix中的数据获取出来

站在客户的角度,才能设计出优良的类(抽象、概念)。

3. matrix的实现方式

a. matrix接口初步

根据第二节的分析,我们的matrix的接口应该是这样的:

class matrix

{

 public:
matrix(); //默认构造函数
matrix(int nRows, int nCols); //构造nRows行、nCols列的矩阵,所有元素初始化为0
matrix(int nRows, int nCols, double* pdArray);//构造nRows行、nCols列的矩阵,矩阵元素为数组的内容
matrix(const matrix& other); //拷贝构造函数,允许使用matrix对象构造
void setMatrix(int nRows, int nCols, double* pdArray); //设置矩阵的大小和数据
void setSize(int nRows, int nCols); //设置矩阵的大小,以后再设置数据
void setData(double* pdArray, ); //设置数据
Size getSize(); //返回矩阵的大小
void getData(double* pdArray); //获得矩阵的数据

operator VARIANT(); //类型转换运算符,允许在函数的输入参数中使用VARIANT的地方使用matrix
                    //matlab com的接口函数的输入参数都是VARIANT型的变量
VARIANT* operator&(); //取地址运算符重载,允许在函数的输出参数中使用VARIANT的地方使用matrix
                     //matlab com的接口函数的输出参数都是VARIANT型的变量的指针(取地址)

}

b.增加一维数组和二维数组的描述

i.一维数组和二维数组的区别

在《Matlab与VC混合编程之二》中我们提到了VARIANT存储数组时是按照列优先的顺序来存储的。如果是一维数据,不管是按照行优先原则还是列优先的原则,访问其内部元素的顺序是相同的。比如double a[3]={1,2,3}。若按照行优先来存储,先存储第一行,那么在内存中的顺序是1,2,3.若按照列优先来存储,先存储第一列,1,再存储第二列2,最后存储第三列3,元素在内存中的顺序依然是1,2,3.所以对于一维数组,不需要进行数据转换。

对于二维数据(矩阵),则必须进行数据转换。仍然使用《Matlab与VC混合编程之二》中的例子。一个3行2列的数组(矩阵)

double array[3][2] = {1, 2,

                      3, 4,

                      5, 6};

按照行优先的顺序存储,在VC中是先存第1{1,2},再存第2{3,4},再存第3{5,6}。即在内存中的顺序是1,2,3,4,5,6.

如果直接将array的数据拷贝到VARIANT的SAFEARRAY中,那么SAFEARRAY在内存中的顺序仍然是1,2,3,4,5,6.但由于SAFEARRAY是按照列优先来存放和访问的。SAFEARRAY的第一维是列,列数是2,第二维是行,行数是3。SAFEARRAY在进行访问时,先访问第1{1,2,3},再访问第2{4,5,6}。即这时将SAFEARRAY写成矩阵的形式是

[1 4,

2 5,

3 6]。显然不是我们要传入的矩阵array.所以,在从二维数组到SAFEARRAY的赋值前必须进行转换。

现在首先对array取转置,得到二维数组b[2][3]={1,3,5,

                                           2,4,6}。之后将b的内存直接拷贝到VARIANT的SAFEARRAY中。由于b在内存中的顺序是1,3,5,2,4,6.那么SAFEARRAY是按照列优先来访问,先访问第1列{1,3,5},再访问第2列{2,4,6}.写成矩阵的形式是

[1,2,

 3,4,

 5,6]。正好是我们所要传入的矩阵。所以转换的方法是,首先将二维数组array求转置得到新的二维数组,将该二维数组的数据直接拷贝到SAFEARRAY中。同时,在输出数据时,需要将SAFEARRAY的数据拷贝出来,经过转置,放置到接受输出数据的二维数组中。见图2.

Matlab与VC混合编程之三
图2 matrix实现示意图

为了区分一维数组和二维数组,定义了枚举enum ArrayType{Dim1, Dim2}; 当使用matrix表示向量(行向量或者列向量,默认是列向量)或者标量时,使用Dim1,表示(Dimension 1,一维)。当使用matrix表示矩阵时,如果用户没有在外部对输入的二维数组使用转置,使用Dim2,matrix会在构造时进行装置;如果用户在外部自己实现了转置,那么使用Dim1,matrix不会再进行转置。即Dim1和Dim2的区别是Dim1构造时matrix时直接拷贝传入的数组的数据,Dim2将传入的数据转置后拷贝到内部的VARIANT。

ii. 数组维数的描述

使用了matrix的内部类struct Size来描述数组的行数和列数。

class matrix {

public:

struct Size
{
int m_nRows; //矩阵的行数
int m_nCols; //矩阵的列数
Size() : m_nRows(0), m_nCols(0){ }
Size(int nRows, int nCols) : m_nRows(nRows), m_nCols(nCols){ }
};

};
c. 兼容已有的程序

为了兼容已有的程序,需要增加VARIANT和matrix互相赋值的接口。使用构造函数和setMatrix函数重载来用VARIANT构造和设置matrix;使用类型转换运算符来将matrix转换为VARIANT。

d. 完整接口的matirx

经过以上分析,具备较完备接口的matrix的定义如下:

class matrix
{
public:
//Dim1:一维数组,表示向量;Dim2:二维数组,表示矩阵。将标量看成是只有一个元素的向量或者矩阵。
enum ArrayType{Dim1, Dim2};
struct Size
{
int m_nRows; //矩阵的行数
int m_nCols; //矩阵的列数
Size() : m_nRows(0), m_nCols(0){ }
Size(int nRows, int nCols) : m_nRows(nRows), m_nCols(nCols){ }
};
public:
matrix();
matrix(int nRows, int nCols); //构造nRows行、nCols列的矩阵,所有元素初始化为0
//构造nRows行、nCols列的矩阵,所有元素初始化为一维数组或二维数组的内容
matrix(int nRows, int nCols, double* pdArray, ArrayType arrType);
matrix(const VARIANT& var); //用VARIANT构造
matrix(const matrix& other); //拷贝构造函数,允许使用matrix对象构造
void setMatrix(int nRows, int nCols, double* pdArray, ArrayType arrType); //设置矩阵的大小和数据
void setMatirx(const VARIANT& var); //用VARIANT设置矩阵
void setSize(int nRows, int nCols); //设置矩阵的大小,默认构造后再设置数据
void setData(double* pdArray, ArrayType arrType); //默认构造后再设置数据
Size getSize(); //返回矩阵的大小
void getData(double* pdArray, ArrayType arrType); //获得矩阵的数据
public: //matrix 与 VARIANT的转换
operator VARIANT(); //类型转换运算符,允许在函数的输入参数中使用VARIANT的地方使用matrix
                   //matlab com的接口函数的输入参数都是VARIANT型的变量
VARIANT* operator&(); //取地址运算符重载,允许在函数的输出参数中使用VARIANT的地方使用matrix
                      //matlab com的接口函数的输出参数都是VARIANT型的变量的指针(取地址)

matrix& operator=(const matrix& other); //重载赋值运算符,允许matrix之间相互赋值

virtual ~matrix();
};

 

4. 优雅的使用matrix类

为了演示matrix的使用,这里使用matrix重写了《Matlab与VC混合编程之二》中的OnButtonTest()。

 void CTestMyCalcDlg::OnButtonTest()
{
 ::CoInitialize(NULL);  //a.初始化COM。
 IMyCalc *pICalc;  //声明一个接口
 
 //b.创建COM接口。
 HRESULT hr = ::CoCreateInstance(CLSID_MyCalc,  //你使用的COM对象的ID(CLaSs ID) 
  NULL, 
  CLSCTX_ALL, 
  IID_IMyCalc, //你使用的COMCOM对象接口的ID(Interface ID) 
  (LPVOID*)&pICalc);//这里用&pIdraw使pIdraw指向接口的地址
 if (FAILED(hr))  //错误检查并处理
 
  //。。。
  return;
 }
 
 //c.使用COM接口,这一段使用的数据类型是VARIANT
 long nvar = 1;  //输出变量的个数
 //i. 使用mycross
 matrix ca,cb,cy; //ca,cb输入参数,cy输出参数初始化在默认构造函数已经完成
 //对向量ca,cb赋值,以double型为例
 //...Action_1
 double array1[3] = {1, 0, 0};    //待存入的一维数组
 double array2[3] = {0, 1, 0};    //带存入的一维数组
 ca.setMatrix(1,3,array1, matrix::Dim1);  //数组维数定义和数据变换自动完成,行向量
 cb.setMatrix(1,3,array2, matrix::Dim1);  //这里也可以将ca、cb定义成列向量,setMatrix(3,1,...);
 hr = pICalc->mycross(nvar, &cy, ca, cb); //输出变量使用&cy形式才能得到返回值。
 //从cy获取计算结果
 //...Action_2
 double array3[3] = {0};
 cy.getData(array3, matrix::Dim1);
 matrix::Size s1 = cy.getSize();
 //array3结果是{0,0,1},结果正确。

 //ii. 使用mydet
 matrix dx,dy; //dx输入参数,dy输出参数, 默认构造函数完成初始化
 //对向量dx赋值,以double型为例
 //...Action_3
 double array4[2][2] = {1, 0, 0, 4};
 dx.setMatrix(2,2,(double*)array4, matrix::Dim2);  //数组维数定义和数据变换自动完成
 hr = pICalc->mydet(nvar, &dy, dx); //输出变量使用&dy形式才能得到返回值。
 //从dy获取计算结果
 //...Action_4
 double dresult = 0;
 dy.getData(&dresult, matrix::Dim1);
 matrix::Size s2 = dy.getSize();
 //dresult = 4,结果正确
 

 //iii. 使用myinv
 matrix ix,iy; //ix输入参数,iy输出参数。ix,iy在默认构造函数已经被初始化
 //对向量ix赋值,以double型为例
 //Action_5
 double array5[3][3] = {1, 0, 0, 0, 1, 0, 0, 0, 1};
 ix.setMatrix(3, 3, (double*)array5, matrix::Dim2);  //数组维数定义和数据变换自动完成
 hr = pICalc->myinv(nvar, &iy, ix); //输出变量使用&iy形式才能得到返回值。
 //从iy获取计算结果
 //...Action_6
 double array6[3][3] = {0};
 iy.getData((double*)array6, matrix::Dim2);
 matrix::Size s3 = iy.getSize();
 //array6结果是{{1,0,0}, {0,1,0}, {0,0,1}},结果正确。


 //d.退出COM。
 CoUninitialize();
}

5. 优雅的背后,matrix封装类

在第4节,我们使用matrix类的接口重写了《Matlab与VC混合编程之二》中VC与Matlab COM的接口函数进行交互的程序。可以明显看到,使用了matrix后,程序代码和程序逻辑得到很大的改善。那么,matrix的接口是怎么实现的。附录8给出优雅的背后,matrix的完整实现代码。

6. 有没有完整的说明matlab COM?

我们采用COM组件方式的matlab与VC混合编程给予了详细的介绍。这里距离完整还差一点,就是我们的程序怎么发布。在Matlab7.0及以下版本中,在Matlab COM Builder窗口中点击菜单Component->Package component;在在Matlab2007b及以上版本中,点击工具栏Build后面的Package按钮。弹出Package Files对话框(Matlab 7.0版本),见图3,将“Include MCR”选中,点击左下方的Create,等待几十秒,完成COM组件封装。在Matlab的当前目录Current Directary窗口下,找到distrib文件夹下的组件名的可执行程序YourComName.exe,将该文件复制出来,跟你的VC程序编译链接生成的可执行程序.exe放在一起打包发布就行了。

Matlab与VC混合编程之三
图3 matlab com package 窗口

7.其他的VC和Matlab混合编程的方式呢?

对于matlab与VC混合编程的实现方法之一“采用COM组件方式”,我们给予了完整而详细的介绍。根据存在必有其意义的想法,其他的混合编程方式一定有其存在的意义。那么其他方式是怎么实现的,有没有优点,接下来的章节会继续探讨。

8.附录

// matrix.h: interface for the matrix class and matrix-related functions.
// 头文件
//
#ifndef MATRIX_H_H
#define MATRIX_H_H

//封装了与matlab com进行交互的数据。可以把所有matlab的函数的输入参数和返回值看成是矩阵形式。
//作者:张坤
//时间:2013.06.06

class matrix 
{
public:
 //Dim1:一维数组,表示向量;Dim2:二维数组,表示矩阵。将标量看成是只有一个元素的向量或者矩阵。
 enum ArrayType{Dim1, Dim2}; 
 struct Size
 {
  int m_nRows;         //矩阵的行数
  int m_nCols;         //矩阵的列数
  Size() : m_nRows(0), m_nCols(0){ }
  Size(int nRows, int nCols) : m_nRows(nRows), m_nCols(nCols){ }
 };
public:
 matrix();
 matrix(int nRows, int nCols);  //构造nRows行、nCols列的矩阵,所有元素初始化为0
 //构造nRows行、nCols列的矩阵,所有元素初始化为一维数组或二维数组的内容
 matrix(int nRows, int nCols, double* pdArray, ArrayType arrType);
 matrix(const VARIANT& var);  //用VARIANT构造
 matrix(const matrix& other); //拷贝构造函数,允许使用matrix对象构造
 void setMatrix(int nRows, int nCols, double* pdArray, ArrayType arrType); //设置矩阵的大小和数据
 void setMatirx(const VARIANT& var); //用VARIANT设置矩阵
 void setSize(int nRows, int nCols);  //设置矩阵的大小,默认构造后再设置数据
 void setData(double* pdArray, ArrayType arrType);  //默认构造后再设置数据
 Size getSize();   //返回矩阵的大小
 void getData(double* pdArray, ArrayType arrType);  //获得矩阵的数据
public:  //matrix 与 VARIANT的转换
 operator VARIANT()  //类型转换运算符,允许在函数的输入参数中使用VARIANT的地方使用matrix
                   //matlab com的接口函数的输入参数都是VARIANT型的变量
  return m_varMatrix;
 }
    VARIANT* operator&() //取地址运算符重载,允许在函数的输出参数中使用VARIANT的地方使用matrix
                    //matlab com的接口函数的输出参数都是VARIANT型的变量的指针(取地址)
  return &m_varMatrix;
 }

 matrix& operator=(const matrix& other);  //重载赋值运算符,允许matrix之间相互赋值

 virtual ~matrix();

private:  //注意:私有函数不属于类的接口,属于类的实现部分
 Size m_matrixSize;   //矩阵的大小,包括行和列
 VARIANT m_varMatrix; //变体类型,与matlab的接口
 //私有函数,将nRow行、nCols列的pdin矩阵转置成pdout矩阵
 inline void transpose(int nRows, int nCols, double* pdin, double* pdout);
 inline void copy(const matrix& other);  //复制other到this对象
 inline void getVariantSize(Size& varSize, const VARIANT& var); //获得该var的大小
};

#endif

 

// matrix.cpp: implementation of the matrix class.
//源文件
//

#include "stdafx.h"
#include "matrix.h"


// 功能:构造0行、0列的空矩阵
// 输入:无
// 输出:无
// 影响:matrix为空矩阵
// 作者:张坤
// 时间:2013.06.06

matrix::matrix()
{
 VariantInit(&m_varMatrix); //一定要初始化
}


// 功能:析构
// 输入:无
// 输出:无
// 影响:无
// 作者:张坤
// 时间:2013.06.06

matrix::~matrix()
{
 VariantClear(&m_varMatrix);
}


// 功能:构造nRows行、nCols列的矩阵,所有元素初始化为0
// 输入:nRows, 矩阵的行数; nCols,矩阵的列数
// 输出:无
// 影响:matrix所有元素初始化为0
// 作者:张坤
// 时间:2013.06.06

matrix::matrix(int nRows, int nCols)
{
 setSize(nRows, nCols);
}


// 功能:拷贝构造函数,允许使用matrix构造
// 输入:matrix对象
// 输出:无
// 影响:matrix大小和所有元素与输入参数相同
// 作者:张坤
// 时间:2013.06.06

matrix::matrix(const matrix& other)
{
 copy(other);
}


// 功能:重载赋值运算符,允许matrix之间相互赋值
// 输入:matrix对象
// 输出:无
// 影响:matrix大小和所有元素与输入参数相同
// 作者:张坤
// 时间:2013.06.06

matrix& matrix::operator=(const matrix& other)
{
 if (this == &other ) //判断是否自身赋值给自身
 {
  return *this;
 }
 else
 {
  copy(other);
  return *this;
 }
}


// 功能:拷贝另一个matrix对象到this对象
// 输入:matrix对象
// 输出:无
// 影响:matrix大小和所有元素与输入参数相同
// 作者:张坤
// 时间:2013.06.06

void matrix::copy(const matrix& other)
{
 m_matrixSize.m_nRows = other.m_matrixSize.m_nRows;
 m_matrixSize.m_nCols = other.m_matrixSize.m_nCols;
 VariantCopy(&m_varMatrix, (VARIANT*)&other.m_varMatrix);
}


// 功能:用指定的var构造矩阵
// 输入:var:VARIANT型的数据
// 输出:无
// 影响:将matrix的大小和所有元素初始化为var的大小和元素
// 作者:张坤
// 时间:2013.06.12

matrix::matrix(const VARIANT& var)
{
 setMatirx(var);
}


// 功能:构造nRows行、nCols列的矩阵,所有元素初始化为一维数组或二维数组的内容
// 输入:nRows, 矩阵的行数; nCols,矩阵的列数,pdArray一维数组或二维数组强制转换的结果,
//    arrType,一维数组或二维数组的标识
// 输出:无
// 影响:matrix所有元素初始化为一维数组或二维数组的内容
// 注意:如果matrix表示一个向量,使用一维数组构造,arrType设为matrix::Dim1
//       若干matrix表示一个矩阵,使用二维数组构造,arrType设为matrix::Dim2
// 作者:张坤
// 时间:2013.06.06

matrix::matrix(int nRows, int nCols, double* pdArray, ArrayType arrType)
    : m_matrixSize(nRows, nCols)
{
 setMatrix(nRows, nCols, pdArray, arrType);
}


// 功能:设置nRows行、nCols列的矩阵,元素为一维数组或二维数组的内容
// 输入:nRows, 矩阵的行数; nCols,矩阵的列数,pdArray一维数组或二维数组强制转换的结果,
// arrType,一维数组或二维数组的标识
// 输出:无
// 影响:matrix所有元素初始化为一维数组或二维数组的内容
// 注意:如果matrix表示一个向量,使用一维数组构造,arrType设为matrix::Dim1
//       若干matrix表示一个矩阵,使用二维数组构造,arrType设为matrix::Dim2
// 作者:张坤
// 时间:2013.06.06

void matrix::setMatrix(int nRows, int nCols, double* pdArray, ArrayType arrType)  //默认构造后再设置数据
{
 setSize(nRows, nCols);
 setData(pdArray, arrType);
}


// 功能:获得指定var的大小
// 输入:varSize引用:var的大小,是返回值;var:欲获得大小的VARIANT
// 输出:无
// 影响:无
// 作者:张坤
// 时间:2013.06.12

void matrix::getVariantSize(Size& varSize, const VARIANT& var) //获得该var的大小
{
 //var是标量
 if (var.vt == VT_R8) 
 {
  varSize.m_nRows = 1;
  varSize.m_nCols = 1;
 }
 else if (var.vt == (VT_R8|VT_ARRAY)
  && var.parray->cDims == 1)  //一维数组,相当于列向量
 {
  varSize.m_nRows = 1;
  varSize.m_nCols = var.parray->rgsabound[0].cElements;
 }
 else //二维数组,矩阵
 {
  varSize.m_nRows = var.parray->rgsabound[1].cElements;
  varSize.m_nCols = var.parray->rgsabound[0].cElements;
 
}


// 功能:用指定的var设定矩阵
// 输入:var:VARIANT型的数据
// 输出:无
// 影响:将matrix的大小和所有元素设置为var的大小和元素
// 作者:张坤
// 时间:2013.06.12

void matrix::setMatirx(const VARIANT& var) //用VARIANT设置矩阵
{
 getVariantSize(m_matrixSize, var);
 VariantCopy(&m_varMatrix, (VARIANT*)&var);
}

// 功能:设置矩阵的所有元素为一维数组或二维数组的内容
// 输入:nRows, 矩阵的行数; nCols,矩阵的列数
// 输出:无
// 影响:matrix为空,只是定义了大小,必须之后再调用setData()
// 注意:这里用一维数组构造时,形参的格式必须按照列优先的顺序构造。
// 作者:张坤
// 时间:2013.06.06

void matrix::setSize(int nRows, int nCols)  //默认构造后再设置数据
{
 m_matrixSize.m_nRows = nRows;
 m_matrixSize.m_nCols = nCols;
 SAFEARRAYBOUND rgsabound[2]; //2 dim array 二维数组的标识
 rgsabound[0].lLbound = 0;    //初始下标从0开始
 rgsabound[0].cElements = m_matrixSize.m_nRows;  //1st dim size 第一维的大小
 rgsabound[1].lLbound = 0;    //初始下标从0开始
 rgsabound[1].cElements = m_matrixSize.m_nCols;  //2nd dim size 第二维的大小
 m_varMatrix.vt = VT_R8|VT_ARRAY;    //double型的二维数组类型的声明
 m_varMatrix.parray = SafeArrayCreate(VT_R8, 2, rgsabound);  //double型的二维数组数据的声明
 
 //初始化为全0
 double* pdBuf = NULL;  //指针用来指向m_varMatrix.parray的数据区
 ::SafeArrayAccessData(m_varMatrix.parray, (void **)&pdBuf);
 memset((void*)pdBuf, 0, m_matrixSize.m_nRows*m_matrixSize.m_nCols*sizeof(double)); //直接设置数据区为全0,也可用循环实现
 ::SafeArrayUnaccessData(m_varMatrix.parray);
}


// 功能:设置矩阵的所有元素为一维数组或二维数组的内容
// 输入:pdArray一维数组或二维数组强制转换的结果,
//    arrType,一维数组或二维数组的标识
// 输出:无
// 影响:matrix所有元素设置为一维数组或二维数组的内容
// 注意:这里用一维数组构造时,形参的格式必须按照列优先的顺序构造。
// 作者:张坤
// 时间:2013.06.06

void matrix::setData(double* pdArray, ArrayType arrType)  //默认构造后再设置数据
{
 double* pdBuf = NULL;  //指针用来指向m_varMatrix.parray的数据区
 ::SafeArrayAccessData(m_varMatrix.parray, (void **)&pdBuf);
 if (arrType == Dim1)   //这里一定要注意pdArray 是存储矩阵元素的一维数组,其排列顺序必须是列优先的。
 {
  memcpy((void*)pdBuf, pdArray, m_matrixSize.m_nRows*m_matrixSize.m_nCols*sizeof(double)); //直接赋值pdArray指向的数据区
 }
 else // arrType == Dim2
 {
  //由于C++二维数组是按行优先顺序来存储的,所以需要转置为列优先的顺序。
  transpose(m_matrixSize.m_nRows, m_matrixSize.m_nCols, pdArray, pdBuf);
 
 ::SafeArrayUnaccessData(m_varMatrix.parray);
}


// 功能:获得矩阵的数据, 返回值矩阵可以为一维数组或二维数组
// 输入:pdArray一维数组或二维数组强制转换的结果,
//    arrType,一维数组或二维数组的标识
// 输出:无
// 影响:无
// 注意:这里用一维数组构造时,形参的格式是按照列优先的顺序排列的。
// 作者:张坤
// 时间:2013.06.07

void matrix::getData(double* pdArray, ArrayType arrType)  //获得矩阵的数据
{
 getSize();  //获取数组的大小
 if (m_varMatrix.vt == VT_R8)  //特殊情况,标量值,不是VT_R8|VT_ARRAY
 {
  pdArray[0] = m_varMatrix.dblVal;
  return;
 } //特殊情况处理结束

 double* pdBuf = NULL;
 ::SafeArrayAccessData(m_varMatrix.parray, (void **)&pdBuf);
 if (arrType == Dim1)
 {
  memcpy(pdArray, pdBuf, m_matrixSize.m_nRows*m_matrixSize.m_nCols*sizeof(double));
 }
 else //arrType == Dim2
   //从列优先的存储转换为行优先的存储
  transpose(m_matrixSize.m_nCols, m_matrixSize.m_nRows, pdBuf, pdArray);
 }
 
 ::SafeArrayUnaccessData(m_varMatrix.parray);
}


// 功能:获得矩阵的维数
// 输入:pdArray一维数组或二维数组强制转换的结果,
//    arrType,一维数组或二维数组的标识
// 输出:无
// 影响:无
// 注意:这里用一维数组构造时,形参的格式是按照列优先的顺序排列的。
// 作者:张坤
// 时间:2013.06.07

matrix::Size matrix::getSize()
{
 //若还未获取作为返回值的matrix封装的m_varMatrix的大小,获取之
 if (m_matrixSize.m_nRows == 0 || m_matrixSize.m_nCols == 0) 
 {
  getVariantSize(m_matrixSize, m_varMatrix);
 }

 //已经获取作为返回值的matrix封装的m_varMatrix的大小,或者是作为输入变量的matrix。
 //直接返回m_matrixSize
 return m_matrixSize;
}


// 功能:将nRow行、nCols列的pdin矩阵转置成pdout矩阵
// 输入:pdin待转置的矩阵,nRows、nCols为pdin的行数和列数
//    pdout为转置的结果, pdout为nCols行、nRows列.
// 输出:无
// 影响:无
// 注意:该函数可以实现行优先与列优先访问时的数据变换,在getData,setData
//    和构造函数中使用。
// 作者:张坤
// 时间:2013.06.11

void matrix::transpose(int nRows, int nCols, double* pdin, double* pdout)
{
 for (int i = 0; i < nRows; ++i)  //第i行
 {
  for (int j = 0; j < nCols; ++j)//第j列
  {
   pdout[j*nRows + i] =  pdin[i*nCols + j];
  }
 }
}

  

本文是作者原创,转载必须保证文章的完整性并标明出处(blog.sina.com.cn/zhangkunhn),请尊重作者,支持原创。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值