【矩阵乘法】C++实现外部矩阵乘法

这篇具有很好参考价值的文章主要介绍了【矩阵乘法】C++实现外部矩阵乘法。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

问题描述

​ 使用文件和内存模拟系统缓存,并利用矩阵乘法验证实际和理论情况。

算法思想

设计一个Matrix类,其中Matrix是存在磁盘中的一个二进制文件,类通过保存的矩阵属性来读取磁盘。前八个字节为两个int32,保存矩阵的行列数。

矩阵乘法 测试用例,小型项目,矩阵,c++,线性代数,缓存,大数据

Matrix中有一个buffer成员为读取到的数据缓存,通过pos属性来确定其在矩阵中的位置。其映射逻辑为 r o w = ⌊ p o s ÷ c o l S i z e ⌋ , c o l = p o s m o d    c o l S i z e row=\lfloor pos \div colSize\rfloor, col=pos \mod colSize row=pos÷colSize,col=posmodcolSize。而缓存的管理模型则是模仿CPU的内存缓存模型,采用写回法。当读取矩阵中rowcol列时,判断逻辑如下。

​ 完成磁盘交互后,其余操作即为正常的矩阵操作

功能模块设计

矩阵类的成员变量,:

    Buffer buffer;
    const int rowSize;
    const int colSize;
    long cacheMissCount; // cache miss 次数
    long cacheCount;     // cache 访问次数
    int pos;             // pos = -1 means invalid buffer
    const int offset = 2 * INT_BYTE;
    fstream file;

​ 矩阵值获取和修改的函数

    int get(int row, int col)
    {
        int index = row * colSize + col;
        assert(index < rowSize * colSize && index >= 0);
        cacheCount++;
        if (index >= pos && index < pos + buffer.size && pos != -1)
            return buffer.get(index - pos);
        else
        {
            cacheMissCount++;
            readBuffer(index);
            return buffer.get(0);
        }
    }
    void set(int row, int col, int val)
    {
        assert(row <= rowSize && col <= colSize);
        if (pos <= indexOf(row, col) && indexOf(row, col) < pos + buffer.size)
            buffer.set(indexOf(row, col) - pos, val);
        else
        {
            cacheMissCount++;
            readBuffer(indexOf(row, col));
            buffer.set(0, val);
        }
        buffer.dirty = true;
    }

​ 磁盘操作函数

    void writeBuffer()
    {
        file.seekp(pos * INT_BYTE + offset, ios::beg);
        for (int i = 0; i < buffer.size; i++)
        {
            file.write((char *)&buffer.get(i), INT_BYTE);
        }
        buffer.dirty = false;
    }

    void readBuffer(int startIndex)
    {
        if (buffer.dirty)
        {
            writeBuffer();
        }

        file.seekg(startIndex * INT_BYTE + offset, ios::beg);
        buffer.size = 0;
        for (int i = 0; i < buffer.capacity && startIndex + i < rowSize * colSize; i++)
        {
            int value;
            file.read((char *)&value, INT_BYTE);
            buffer.set(i, value);
            buffer.size++;
        }
        pos = startIndex;
    }

​ 矩阵乘法函数

    Matrix *multiple_ijk(Matrix &right)
    {
        Matrix *t = new Matrix(rowSize, right.colSize, buffer.capacity);
        int i, j, k;
        for (i = 0; i < rowSize; i++)
        {
            for (j = 0; j < right.colSize; j++)
            {
                for (k = 0; k < right.rowSize; k++)
                {
                    t->set(i, j, t->get(i, j) + get(i, k) * right.get(k, j));
                }
            }
        }
        return t;
    }

    Matrix *multiple_ikj(Matrix &right)
    {
        Matrix *t = new Matrix(rowSize, right.colSize, buffer.capacity);
        int i, j, k;
        for (i = 0; i < rowSize; i++)
        {
            for (k = 0; k < right.rowSize; k++)
            {
                for (j = 0; j < right.colSize; j++)
                {
                    t->set(i, j, t->get(i, j) + get(i, k) * right.get(k, j));
                }
            }
        }
        return t;
    }

测试结果与分析

测试用例

class MatrixTest
{
public:
    void test1()
    {
        Matrix m(10, 10, 3, "m.txt");
        m.randomize();
        cout << m << endl;
        cout << "cache miss:" << m.getCacheMissCount() << endl;
        Matrix m1(10, 10, 3);
        m1.randomize();
        cout << m1 << endl;
        cout << "cache miss:" << m1.getCacheMissCount() << endl;
    }

    void test2()
    {
        Matrix m(10, 10, 3);
        cout << m << endl;
        m.set(0, 0, 9999);
        cout << m << endl;
        m.set(5, 0, 9999);
        cout << m << endl;
        m.set(3, 7, 9999);
        cout << m << endl;
    }
    void test3()
    {
        Matrix m1(2, 3, 5, "m1.txt");
        m1.randomize(100);
        cout << m1 << endl;
        Matrix m2(3, 4, 7, "m2.txt");
        m2.randomize(100);
        cout << m2 << endl;
        Matrix *m3 = m1.multiple_ijk(m2);
        cout << *m3 << endl;
        Matrix *m4 = m1.multiple_ikj(m2);
        cout << *m4 << endl;
        assert(m3->toString() == m4->toString());
    }
    void test4(int n, int cacheSize)
    {
        cout << "cache size is " << cacheSize << endl;
        Matrix m1(n, n, cacheSize, "m1.txt");
        cout << "initial m1(size is " << n << ")finished" << endl;
        Matrix m2(n, n, cacheSize, "m2.txt");
        cout << "initial m2(size is " << n << ")finished" << endl;
        Matrix *m3 = m1.multiple_ijk(m2);
        cout << "m1 ijk m2 finished" << endl;
        cout << "cache coutnt of m1: " << m1.getCacheCount() << ",	cache miss count of m1:" << m1.getCacheMissCount() << endl;
        cout << "cache coutnt of m2: " << m2.getCacheCount() << ",	cache miss count of m2:" << m2.getCacheMissCount() << endl;
        cout << "cache coutnt of m3: " << m3->getCacheCount() << ",	cache miss count of m3:" << m3->getCacheMissCount() << endl;
        cout << endl;
    }
    void test5(int n, int cacheSize)
    {
        cout << "cache size is " << cacheSize << endl;
        Matrix m1(n, n, cacheSize, "m1.txt");
        cout << "initial m1(size is " << n << ")finished" << endl;
        Matrix m2(n, n, cacheSize, "m2.txt");
        cout << "initial m2 finished" << endl;
        Matrix *m3 = m1.multiple_ikj(m2);
        cout << "m1 ijk m2(size is " << n << ")finished" << endl;
        cout << "cache coutnt of m1: " << m1.getCacheCount() << ",	cache miss count of m1:" << m1.getCacheMissCount() << endl;
        cout << "cache coutnt of m2: " << m2.getCacheCount() << ",	cache miss count of m2:" << m2.getCacheMissCount() << endl;
        cout << "cache coutnt of m3: " << m3->getCacheCount() << ",	cache miss count of m3:" << m3->getCacheMissCount() << endl;
        cout << endl;
    }
    void runTest()
    {
        for (int i = 5; i < 35; i += 5)
        {
            for (int j = 1; j < 5; j++)
            {
                test4(i, i / j);
                test5(i, i / j);
            }
        }
    }
};

实验测试

矩阵乘法 测试用例,小型项目,矩阵,c++,线性代数,缓存,大数据

矩阵乘法 测试用例,小型项目,矩阵,c++,线性代数,缓存,大数据

实验分析

假设矩阵为 C = A × B C=A\times B C=A×B,且cache大小小于矩阵的一行或一列,且A、B、C都是大小为n的方阵

对于ijk的情况:

​ 每次读取时发生一次磁盘访问,而若cache当中有脏数据,则有另一次的写入访问。对于矩阵C,因为其作为操作矩阵*(总是进行+=操作)*,所以只要是C矩阵发生了cache miss其实是进行了两次磁盘访问,而对于AB矩阵,发生cache miss 时只发生一次磁盘访问。

​ cache miss 发生次数如下
C c a c h e   m i s s = n 2 c a c h e   s i z e A c a c h e   m i s s = n 3 c a c h e   s i z e B c a c h e   m i s s = n 3 C_{cache\ miss} = \frac{n^2}{cache\ size}\\ A_{cache\ miss} = \frac{n^3}{cache\ size}\\ B_{cache\ miss} = n^3 Ccache miss=cache sizen2Acache miss=cache sizen3Bcache miss=n3
​ 所消耗的总时间
t t o t a l = 2 T d i s k   a c c e s s   t i m e C c a c h e   m i s s + T d i s k   a c c e s s   t i m e A c a c h e   m i s s + T d i s k   a c c e s s   t i m e B c a c h e   m i s s = n 3 T d i s k   a c c e s s   t i m e c a c h e   s i z e ( 1 + 1 n + c a c h e   s i z e ) t_{total}=2T_{disk\ access\ time}C_{cache\ miss}+T_{disk\ access\ time}A_{cache\ miss}+T_{disk\ access\ time}B_{cache\ miss}\\ =\frac{n^3T_{disk\ access\ time}}{cache\ size(1+\frac{1}{n}+cache\ size)} ttotal=2Tdisk access timeCcache miss+Tdisk access timeAcache miss+Tdisk access timeBcache miss=cache size(1+n1+cache size)n3Tdisk access time
​ 而当顺序化为ijk的时候,B矩阵的cache hit 率有所提高
C c a c h e   m i s s = n 3 c a c h e   s i z e A c a c h e   m i s s = n 2 c a c h e   s i z e B c a c h e   m i s s = n 3 c a c h e   s i z e C_{cache\ miss} = \frac{n^3}{cache\ size}\\ A_{cache\ miss} = \frac{n^2}{cache\ size}\\ B_{cache\ miss} = \frac{n^3}{cache\ size} Ccache miss=cache sizen3Acache miss=cache sizen2Bcache miss=cache sizen3
所消耗的总时间变为了
t t o t a l = 2 T d i s k   a c c e s s   t i m e C c a c h e   m i s s + T d i s k   a c c e s s   t i m e A c a c h e   m i s s + T d i s k   a c c e s s   t i m e B c a c h e   m i s s = n 3 T d i s k   a c c e s s   t i m e c a c h e   s i z e ( 2 + 1 n ) t_{total}=2T_{disk\ access\ time}C_{cache\ miss}+T_{disk\ access\ time}A_{cache\ miss}+T_{disk\ access\ time}B_{cache\ miss}\\ =\frac{n^3T_{disk\ access\ time}}{cache\ size(2+\frac{1}{n})} ttotal=2Tdisk access timeCcache miss+Tdisk access timeAcache miss+Tdisk access timeBcache miss=cache size(2+n1)n3Tdisk access time文章来源地址https://www.toymoban.com/news/detail-678391.html

到了这里,关于【矩阵乘法】C++实现外部矩阵乘法的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【C++】矩阵的乘法

    先复习一下矩阵的乘法 。 已知 求AB。  因为矩阵A是2×3矩阵,矩阵B是3×3矩阵,A的列数等于B的行数,所以矩阵A与B可以相乘,乘积AB是一个2×3矩阵。 矩阵相乘时需要注意两点,一点是矩阵1的列数要等与矩阵2的行数,一点是矩阵相乘后的矩阵 c[i][j] = a[i][k]*b[k][j]   由矩阵相

    2024年02月12日
    浏览(22)
  • 简单的小型C++项目怎么用CMAKE进行管理

    根目录下共有两个文件夹,分别为include、src,有两个文件,分别为CMakeLists.txt和main.cpp 可以看出,include了func.h,且func.h的声明在include文件夹下,定义在src文件夹下的func.cpp中 add_library 表示创建了一个静态库,名字是func,用的是func.cpp这个文件 target_include_directories 表示让 ..

    2023年04月22日
    浏览(36)
  • 【矩阵快速幂】封装类及测试用例及样例

    视频算法专题 通俗的说,就是矩阵的乘方。 题目、分析和原理见: 【动态规划】【矩阵快速幂】【滚动向量】C++算法552. 学生出勤记录 II 原解法用二维表示状态,改成一维。 i是缺勤数量,j是连续迟到数,新的状态为:3*i+j 6种状态,故转移矩阵为6行6列,故结果矩阵为6列,

    2024年01月22日
    浏览(27)
  • 矩阵乘法实现卷积运算

            矩阵根据卷积核的大小进行,从左到右、从上到i 下 的移动,对应数据相乘再相加得到的数据为该区域的值。 ​​​​​​​ ​​​​​​​         原理:根据对于相乘相加的机制,发现通过对卷积核填零构成和输入矩阵大小一致的矩阵,然后展平拼接起来,

    2024年02月12日
    浏览(34)
  • 用Java实现矩阵乘法

    矩阵相乘需注意:         1、当矩阵A的列数(column)等于矩阵B的行数(row)时,A与B可以相乘。         2、矩阵C的行数等于矩阵A的行数,C的列数等于B的列数。         3、乘积C的第m行第n列的元素等于矩阵A的第m行的元素与矩阵B的第n列对应元素乘积之和 设a为

    2023年04月08日
    浏览(30)
  • MPI实现矩阵向量乘法

    (1)问题 MPI实现矩阵向量:Ab的乘积。其中A:100行100列,b为列向量。 (2)思路 将所有进程分为两部分,rank=0的进程为master节点,其余进程为worker节点。 master节点: (1)对A,b赋值,同时将b广播出去(这里涉及一个对广播这个函数不太熟悉的点) (2)对A进行划分,使其

    2024年02月11日
    浏览(24)
  • 矩阵乘法,python简易实现

    1.首先,先了解下矩阵乘法最基本的工作原理,可简易得理解成 C矩阵(i, j)的值是 由A矩阵 i 行依次与B矩阵 j 列相乘的求和,即:  2.demo实现 3、基于矩阵结果是行和列的对应相乘的累和迭代,所以选择依次增加,核心算法:      其中,选取 i、j、k进行循环与迭代,k作为中

    2024年02月11日
    浏览(28)
  • 使用cublas实现矩阵乘法

    使用CUDA写一个矩阵乘法 C = A X B (矩阵维度: A: M X K, B: K X N, C: M X N ),当然可以自己写核函数,但效率不如CUDA自带的 cublas 算法效率高。使用 cublas 唯一值得注意的地方是, 在CPU中的矩阵数据存储是行优先存储,而在GPU中是列优先存储 ,这相当于对原矩阵做了一次转置,我

    2024年02月16日
    浏览(26)
  • markdown实现矩阵乘法

    [ x y 1 ] = [ f 0 O x 0 f O y 0 0 1 ] [ x ˉ y ˉ z ] (1) left[ begin{matrix} x \\\\ y \\\\ 1 end{matrix} right] = left[ begin{matrix} f 0 O_x\\\\ 0 f O_y\\\\ 0 0 1 end{matrix} right] left[ begin{matrix} bar{x} \\\\ bar{y} \\\\ z end{matrix} right] tag{1} ​ x y 1 ​ ​ = ​ f 0 0 ​ 0 f 0 ​ O x ​ O y ​ 1 ​ ​ ​ x ˉ y ˉ ​ z ​ ​ ( 1

    2024年02月09日
    浏览(25)
  • 【Python】矩阵乘法3种实现方案

    结论: 1、@ 符在numpy里就是矩阵乘法的意思,也是dot()的意思。 2、用这个 @ 运算符可以不用再使用matmult方法 3、一般来说,@ 比.dot()方法要慢一点点。dot是numpy里的函数,主要用于求向量相乘,矩阵乘法,矩阵与向量乘法。   内积,点积,乘法, 点积 对于元素相乘并相加,

    2024年02月12日
    浏览(33)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包