`
qiezi
  • 浏览: 497815 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

泛型矩阵类

    博客分类:
  • c++
阅读更多

矩阵就不用再解释了,写成泛型主要是为了几个方便:
1、方便在栈上分配空间。由于维度在编译期已知,所以可以做到在栈上分配空间。当然如果这个对象是new出来的,自然是在堆上分配,这里说的是在栈上分配这个对象时,矩阵元素所占用的空间也在栈上分配。
2、方便在编译期检查非法的矩阵运算。C++模板的强大推导能力可以在编译期推导出结果矩阵的维度。
3、泛型类在方法内联上具有优势。

这个矩阵类为了能够直接从数组赋值,使用了一个ArrayPorxy类(可参考《Imperfect C++》)。

代码如下:

template  < class  T,  int  D1,  int  D2 = 1 >
class  ArrayProxy
{
    T
*  data;
public :
    ArrayProxy(T (
& value)[D1][D2])
        : data(
& value[ 0 ][ 0 ])
    {
    }

    ArrayProxy(T (
& value)[D1 * D2])
        : data(value)
    {
    }

    T
*  getData()  const
    {
        
return  data;
    }
};

这个只是简单的实现。

因为我基本上不使用这个矩阵类,所以只完成几个简单功能:
1、从数组赋值:
int a[][3] = {{1,2,3}, {4,5,6}};
Matrix<int, 2, 3> m1(a);

int a[] = {1,2,3, 4,5,6};
Matrix<int, 2, 3> m1(a);
Matrix<int, 3, 2> m2(a);
Matrix<int, 6, 1> m3(a);
Matrix<int, 1, 6> m4(a);

2、矩阵乘法:
Matrix<int, 2, 3> m1;
Matrix<int, 2, 4> m2;
// m1 * m2  <== 编译错误,维度不匹配
Matrix<int, 3, 5> m3;
Matrix<int, 2, 5> m4 = m1 * m3; // <== 合法
// m3 * m1; // <== 编译错误,维度不匹配

源码如下:

template <class T, int R, int C>
class Matrix
{
    T matrix[R][C];

public:
    
// Big three
    Matrix(void)
    {
        memset(matrix, 
0sizeof(matrix));
    }

    Matrix(
const Matrix& rhs)
    {
        memcpy(matrix, rhs.matrix, 
sizeof(matrix));
    }

    Matrix
& operator =(const Matrix& rhs)
    {
        memcpy(matrix, rhs.matrix, 
sizeof(matrix));
        
return *this;
    }

public:
    Matrix(
const ArrayProxy<T,R,C>& arr)
    {
        memcpy(matrix, arr.getData(), 
sizeof(matrix));
    }

    
~Matrix(void)
    {
    }

public:
    T 
get(int r, int c) const
    {
        assert(c 
< C && c >= 0 && r < R && r >= 0);
        
return matrix[r][c];
    }

    
void set(int r, int c, T v)
    {
        assert(c 
< C && c >= 0 && r < R && r >= 0);
        matrix[r][c] 
= v;
    }

    
int getCols () const
    {
        
return C;
    }

    
int getRows () const
    {
        
return R;
    }

    
bool operator == (const Matrix& rhs) const
    {
        
return memcmp(matrix, rhs.matrix, sizeof(matrix)) == 0;
    }

    
bool operator != (const Matrix& rhs) const
    {
        
return !(*this == rhs);
    }
};

template 
<class T, int R, int C, int C1>
Matrix
<T,R,C1> operator* (const Matrix<T,R,C>& lhs, const Matrix<T,C,C1>& rhs)
{
    Matrix
<T,R,C1> result;
    
for (int r=0; r<R; ++r)
    {
        
for (int c=0; c<C1; ++c)
        {
            
int value = 0;
            
for (int i=0; i<C; ++i)
            {
                value 
+= lhs.get(r,i) * rhs.get(i,c);
            }
            result.
set(r,c,value);
        }
    }
    
return result;
}

测试代码:

int main()
{
    {
        
// 测试初始化
        Matrix<int34> m1;
        Matrix
<int34> m2(m1);
        Matrix
<int34> m3 = m1;
        Matrix
<int34> m4;
        m4 
= m1;

        
for (int i=0; i<3; i++)
            
for (int j=0; j<4; j++)
            {
                assert (m1.
get(i, j) == 0);
                assert (m2.
get(i, j) == 0);
                assert (m3.
get(i, j) == 0);
                assert (m4.
get(i, j) == 0);
            }

        
int a[] = {1,2,3,45,6,7,89,10,11,12};
        Matrix
<int34> m5(a);

        
int b[3][4= { {1,2,3,4},
                        {
5,6,7,8},
                        {
9,10,11,12}};

        Matrix
<int34> m6(b);

        Matrix
<int34> m7(m5);
        Matrix
<int34> m8 = m5;
        Matrix
<int34> m9;
        m9 
= m5;

        
for (int i=0; i<3; i++)
            
for (int j=0; j<4; j++)
            {
                assert (m5.
get(i, j) == i*4+j+1);
                assert (m6.
get(i, j) == i*4+j+1);
                assert (m7.
get(i, j) == i*4+j+1);
                assert (m8.
get(i, j) == i*4+j+1);
                assert (m9.
get(i, j) == i*4+j+1);
            }

        
// 维数不匹配,编译错误
        
// Matrix<int, 4, 5> m10 = m9;
        int c[][2= {{1,2}, {2,3}};
        
// 数组大小不匹配,编译错误
        
//Matrix<int, 3, 4> m10(c);
        int d[] = {1,2};
        
// 数组大小不匹配,编译错误
        
//Matrix<int, 3, 4> m11(d);

        
// 乘法维数不合适,无法相乘
        
//m1 * m2;

        Matrix
<int,4,3> m12;
        
// 匹配,可以相乘
        Matrix<int33> m13 = m1 * m12;

        Matrix
<int83> m14;
        
// 无法相乘
        
//Matrix<int, 3, 3> m15 = m1 * m14;
        
// 可以相乘
        Matrix<int84> m15 = m14 * m1;
    }

    {
        
// 检查点乘
        int a[2][5= {{1,2,3,4,5}, {6,7,8,9,10}};
        Matrix
<int25> m1(a);

        
int b[5][3= {{1,2,3}, {4,5,6}, {7,8,9}, {10,11,12}, {13,14,15}};
        Matrix
<int53> m2(b);

        
int c[2][3= {{135,150,165}, {310,350,390}};
        Matrix
<int23> m3(c);

        Matrix
<int23> m4 = m1 * m2;
        assert(m4 
== m3);

        cout 
<< m4.get(0,0<< endl;
    }

    
return 0;
}

补充:
1、加法、减法只需要2个矩阵维度相同即可。
template <class T, class R, class C>
Matrix
<T,R,C> operator+ (const Matrix<T,R,C>& lhs, const Matrix<T,R,C>& rhs)
{
   
// 
}

2、由于1x1的矩阵可以看成一个标量,矩阵与标量运算结果维数与原矩阵相同,可以重载来实现。
template <class T, class R, class C>
Matrix
<T,R,C> operator* (const Matrix<T,R,C>& lhs, const Matrix<T,1,1>& rhs)
{
    
// 
}

3、由于类型泛化,可能某些合理的运算无法进行,比如float型矩阵,与一个int型标量运算等。这些最好是借助类型萃取等手段,推导出运算以后的类型。(c++0x中包含自动获取运算结果类型的关键字typeof,等几年就可以用了:)。GCC编译器中已有实现,不过似乎有BUG)。

4、其它。泛型实现可能会有一些考虑不周的地方,强类型有强类型的好处,不过必须要有完整的泛型算法支撑,否则难以使用。也可以把泛型矩阵类从一个普通矩阵类派生,这样更容易写出通用算法,不过在实现上可能要借助于运行期多态,对于矩阵类来说并不合适。

5、其它。。前面说C++的模板相当强大,D语言模板到目前为止似乎已经完全实现了C++模板的功能,还增加了一些比如字符串值参模板等特性,比C++模板功能更多。在代码编写上,由于可以编写静态判断语句(编译期)以及静态断言,编写模板比C++更容易。有时间可以试试用它写个矩阵类,纯粹是兴趣,这些东西真的很难用到,现成的库也挺多。

6、其它。。。c++0x要提供“template typedef”,也就是可以这样定义:
template <int R, int C> typedef Matrix<int, R, C> MatrixInt;  // 定义类型,维度不定
template <class T> typedef Matrix<T, 4, 4> Matrix4x4; // 定义维度,类型不定
由此可以出定义行向量、列向量、标量等,当然实际使用起来可能没那么舒服了。
分享到:
评论

相关推荐

    矩阵运算的vb及c++代码

    例如,使用模板可以创建泛型矩阵类,实现加法、减法和乘法运算符重载。 - **库支持**:C++有许多库支持矩阵运算,如BLAS(Basic Linear Algebra Subprograms)和LAPACK(Linear Algebra Package),还有更高级的库...

    任意矩阵加法,乘法,逆阵

    用c++,能够实现任意矩阵加法,乘法,逆阵计算。

    C++模板矩阵,实现矩阵的常见运算

    通过模板,我们可以创建一个泛型的矩阵类,支持多种数据类型,并通过重载操作符实现矩阵的加、减、乘、除等运算。同时,我们还可以扩展额外的功能,如矩阵的求逆和点乘。测试程序则确保了矩阵运算的正确性。

    C,C++,C#通用矩阵类

    本资源提供了适用于C,C++,C#三种语言的通用矩阵类,旨在简化矩阵操作并支持矩阵的求逆、转置和乘法等基本运算。下面将详细介绍这些知识点。 1. **矩阵类的设计**: - 矩阵类通常包含矩阵的行数、列数以及存储...

    可以存放字符串等其它数据类性的C++矩阵类

    在C++编程中,设计一个可以存放不同数据类型的矩阵类是一项具有挑战性的任务,因为C++是一种静态类型语言,不支持动态类型。然而,通过使用模板(templates)和继承(inheritance),我们可以创建一个灵活的矩阵类,...

    MTL——C++实现的矩阵模板类

    **MTL——C++实现的矩阵模板类** MTL(Matrix Template Library)是一个强大的C++库,专门用于处理矩阵和线性代数运算。它提供了一组高效的模板类,允许程序员进行各种矩阵运算,包括但不限于加法、减法、乘法、...

    基于C#编程建立泛型Matrix类库

    本文所描述的泛型Vector和泛型Matrix,具有不同数值类型Vector、Matrix矩阵构造、this[,]索引、Copy深度复制、运算符(+加、-减、*乘、&gt;大于、&lt;小于、&gt;=大于等于、小于等于)重载、GetRow提取某一行、GetCol提取某一...

    矩阵测试代码

    这个项目可能涉及的编程任务包括:设计和实现矩阵类(可能包含加、减、乘、转置等方法),编写单元测试以验证矩阵运算的正确性,创建用户界面以便用户输入矩阵并显示结果,以及优化算法以提高性能。通过这个项目,...

    矩阵模板类

    - 缓存友好:设计矩阵类时,应考虑内存访问模式,尽可能使连续访问的元素位于内存的连续位置,以利用缓存的局部性原理提高性能。 - 错误检查:在操作过程中,确保对矩阵的尺寸进行检查,防止非法操作,如非方阵进行...

    C++经典项目——矩阵

    3. **模板类**:为了使矩阵类能处理不同类型的元素(如整型、浮点型等),可以使用模板类来实现泛型编程。 4. **友元函数**:矩阵的加法和乘法操作可能需要访问类的私有成员,可以将这些函数声明为友元函数。 在...

    C++课程设计--矩阵运算器

    5. **模板编程**:为了使矩阵运算器能够处理不同类型的数值(如int、float、double等),可以使用C++的模板机制,这样可以创建泛型的矩阵类,增加代码的复用性。 6. **错误处理**:在实现过程中,需要考虑各种可能...

    C++矩阵库_C++调用矩阵_矩阵函数库_源码.zip

    7. **模板和泛型编程**:C++的模板机制使得矩阵库可以处理不同类型的元素(如浮点数、复数等),实现泛型编程,提高代码的可重用性。 8. **错误处理**:矩阵运算过程中可能会遇到除以零、矩阵非方阵无法求逆等情况...

    C++实现矩阵各种常用运算

    C++的模板功能允许我们编写泛型代码,使得矩阵运算不仅可以应用于基本类型(如int、double),还可以应用于用户自定义的数据类型。 9. **库的使用**: 虽然可以直接用C++基础语法实现矩阵运算,但高级的数值计算...

    matrs:试验Rust的const泛型以实现基于数组的矩阵运算

    例如,我们可以定义一个矩阵类,其维度是const泛型,确保矩阵始终具有固定的行数和列数。 ```rust struct Matrix, const ROWS: usize, const COLS: usize&gt; { data: [[T; COLS]; ROWS], } ``` 在这个结构体中,`T`...

    矩阵求逆:用C++写的能求任意阶的矩阵的逆

    - C++是一种静态类型、编译式的通用编程语言,支持面向对象和泛型编程。 - 在C++中,可以使用二维数组来表示矩阵,利用指针和引用实现高效的数据操作。 - 头文件如`&lt;iostream&gt;`用于输入输出,`&lt;cmath&gt;`提供数学...

    二维矩阵模板

    尽管描述部分似乎没有提供实质性内容,但从部分代码内容中可以看出,这是一个针对线性代数操作设计的矩阵类模板。下面我们将详细解释这些关键知识点。 ### 一、矩阵类模板简介 #### 1. 概述 在计算机科学与数学...

    实现matlab矩阵计算的C++源程序

    为了提高代码的通用性,可以使用C++的模板机制,使得矩阵类可以处理不同类型的元素(如`int`, `float`, `double`等)。 8. **错误处理**: MATLAB会自动处理一些错误,如除以零、矩阵维度不匹配等。在C++中,这些...

    ch3_c++矩阵_

    6. **矩阵类的设计**: 为了提高代码的复用性和易用性,可以创建一个名为`Matrix`的类,封装矩阵的创建、初始化、赋值和运算等操作。类的成员可以包括存储矩阵元素的二维数组,以及相应的成员函数,如`setZero()`...

    矩阵操作C++.pdf

    文档中提到了模板类“TMatrix”,这是一个泛型编程的实现,表示矩阵类可以处理不同数据类型的矩阵。模板(template)允许程序员编写与数据类型无关的代码,这使得同一段代码能够用于多种类型,增强了代码的复用性。 ...

    凑字数Matrix.rar

    分数矩阵运算类:设计矩阵类和分数类,封装矩阵和分数的运用。 目的:掌握面向对象的程序设计思想,运用C#语言的继承-封装-重载-泛型,完成从数学算法到OOP实践。 要求: (1)设计矩阵类Matrix,重载运算符+,-,*...

Global site tag (gtag.js) - Google Analytics