为什么C动态数组乘法比std :: vector版本更好

我正在为具有不同数据结构和技术(向量,数组和OpenMP)的矩阵实现C乘法,我发现一个奇怪的情况…我的动态数组版本工作更好:

时间:

openmp mult_1: time: 5.882000 s

array mult_2: time: 1.478000 s

我的汇编标志是:

/usr/bin/g++ -fopenmp -pthread -std=c++1y -O3

C矢量版本

typedef std::vector<std::vector<float>> matrix_f;
void mult_1 (const matrix_f &  matrixOne,const matrix_f & matrixTwo,matrix_f & result) {
    const int matrixSize = (int)result.size();
    #pragma omp parallel for simd
    for (int rowResult = 0; rowResult < matrixSize; ++rowResult) {
        for (int colResult = 0; colResult < matrixSize; ++colResult) {
            for (int k = 0; k < matrixSize; ++k) {
                result[rowResult][colResult] += matrixOne[rowResult][k] * matrixTwo[k][colResult];  
            }
        }
    }
}

动态阵列版本

void mult_2 ( float *  matrixOne,float * matrixTwo,float * result,int size)  {
    for (int row = 0; row < size; ++row) {
        for (int col = 0; col < size; ++col) {
            for (int k = 0; k < size; ++k) {
                (*(result+(size*row)+col)) += (*(matrixOne+(size*row)+k)) * (*(matrixTwo+(size*k)+col));
            }
        }
    }
}

测试:

C矢量版本

utils::ChronoTimer timer;
/* set Up simple matrix */
utils::matrix::matrix_f matr1 = std::vector<std::vector<float>>(size,std::vector<float>(size));
fillRandomMatrix(matr1);

utils::matrix::matrix_f matr2 = std::vector<std::vector<float>>(size,std::vector<float>(size));
fillRandomMatrix(matr2);

utils::matrix::matrix_f result = std::vector<std::vector<float>>(size,std::vector<float>(size));    
timer.init();
utils::matrix::mult_1(matr1,matr2,result);
std::printf("openmp mult_1: time: %f ms\n",timer.Now() / 1000);

动态阵列版本

utils::ChronoTimer timer;

float *p_matr1 = new float[size*size];
float *p_matr2 = new float[size*size];
float *p_result = new float[size*size];

fillRandomMatrixArray(p_matr1,size);
fillRandomMatrixArray(p_matr2,size);

timer.init();
utils::matrix::mult_2(p_matr1,p_matr2,p_result,size);
std::printf("array mult_2: time: %f ms\n",timer.Now() / 1000);

delete [] p_matr1;
delete [] p_matr2;
delete [] p_result;

我正在检查一些以前的帖子,但我找不到任何与我的问题相关的link,link2,link3

更新:
我重新测试了答案,而矢量作品稍微好一些:

vector mult: time: 1.194000 s

array mult_2: time: 1.202000 s

C矢量版本

void mult (const std::vector<float> &  matrixOne,const std::vector<float> & matrixTwo,std::vector<float> & result,int size) {
    for (int row = 0; row < size; ++row) {
        for (int col = 0; col < size; ++col) {
            for (int k = 0; k <size; ++k) {
                result[(size*row)+col] += matrixOne[(size*row)+k] * matrixTwo[(size*k)+col];
            }
        }
    }
}

动态阵列版本

void mult_2 ( float *  matrixOne,int size)  {
    for (int row = 0; row < size; ++row) {
        for (int col = 0; col < size; ++col) {
            for (int k = 0; k < size; ++k) {
                (*(result+(size*row)+col)) += (*(matrixOne+(size*row)+k)) * (*(matrixTwo+(size*k)+col));
            }
        }
    }
}

此外,我的矢量化版本工作更好(0.803秒);

解决方法

向量向量类似于锯齿状数组 – 每个条目都是一个指针的数组,每个指针指向另一个浮点数组.

相比之下,原始阵列版本是一个内存块,您可以在数学中找到元素.

使用单个向量,而不是向量向量,并手动进行数学运算.或者,使用fix-sized std ::数组的向量.或者写一个需要浮点数(一维)向量的帮助器类型,并给出一个2维视图.

连续缓冲区中的数据比一系列断开连接的缓冲区中的数据更有缓存和优化.

template<std::size_t Dim,class T>
struct multi_dim_array_view_helper {
  std::size_t const* dims;
  T* t;
  std::size_t stride() const {
    return
      multi_dim_array_view_helper<Dim-1,T>{dims+1,nullptr}.stride()
      * *dims;
  }
  multi_dim_array_view_helper<Dim-1,T> operator[](std::size_t i)const{
    return {dims+1,t+i*stride()};
  }
};
template<class T>
struct multi_dim_array_view_helper<1,T> {
  std::size_t stride() const{ return 1; }
  T* t;
  T& operator[](std::size_t i)const{
    return t[i];
  }
  multi_dim_array_view_helper( std::size_t const*,T* p ):t(p) {}
};
template<std::size_t Dims>
using dims_t = std::array<std::size_t,Dims-1>;
template<std::size_t Dims,class T>
struct multi_dim_array_view_storage
{
  dims_t<Dims> storage;
};
template<std::size_t Dims,class T>
struct multi_dim_array_view:
  multi_dim_array_view_storage<Dims,T>,multi_dim_array_view_helper<Dims,T>
{
  multi_dim_array_view( dims_t<Dims> d,T* t ):
    multi_dim_array_view_storage<Dims,T>{std::move(d)},T>{
      this->storage.data(),t
    }
  {}
};

现在你可以这样做:

std::vector<float> blah = {
   01.f,02.f,03.f,11.f,12.f,13.f,21.f,22.f,23.f,};

multi_dim_array_view<2,float> view = { {3},blah.data() };
for (std::size_t i = 0; i < 3; ++i )
{
  std::cout << "[";
  for (std::size_t j = 0; j < 3; ++j )
    std::cout << view[i][j] << ",";
  std::cout << "]\n";
}

live example

在视图类中没有复制数据.它只是提供一个多维数组的平面数组的视图.

相关文章

本程序的编译和运行环境如下(如果有运行方面的问题欢迎在评...
水了一学期的院选修,万万没想到期末考试还有比较硬核的编程...
补充一下,先前文章末尾给出的下载链接的完整代码含有部分C&...
思路如标题所说采用模N取余法,难点是这个除法过程如何实现。...
本篇博客有更新!!!更新后效果图如下: 文章末尾的完整代码...
刚开始学习模块化程序设计时,估计大家都被形参和实参搞迷糊...