如何连续(连贯地)在C++内存中存储三维数组?
这是我第一次使用SO。对不起我的英语,但我会努力尽我所能,并完全为了您的理解,用我的大学任务来描述我的问题。我相信我的问题是更多的代码和数组相关,而不是数学。如何连续(连贯地)在C++内存中存储三维数组?
我正在使用MPI,OpenMP和大尺寸以及网格大小解决立方体中的数值3D波浪问题。现在我正在编写一个代码在我们的大学超级计算机上执行它。
因此一些小的解释和公式来理解问题更好:
- 我有在每个轴上的N + 1个点的立方体(与数字从到Ñ)
- 让我小号 = MPI_size的亲总数与行列正如事实从到S-1
- 我做小号平行区域使切片垂直于Y轴(与固定Ĵ号码)。我的意思是指数我对应x轴,j到y和k到z照常。
- 所以现在与从0到S-1个等级的每个进程负责P =(N + 1)/ s的在我的Y轴点:从秩* P到秩* p + p-1
- 现在我遇到了创建三个大小为[N + 1] [p] [N + 1]的阵列的问题。三,因为在每一步的计算我使用的值从前一个时间步和从“双前(先前的前)”(对不起,我不知道怎么说正确的:))
我试图这样做只是想:
for(int i = 0; i < N_p+1; i++) {
u[i] = new double*[N_p+1];
u_prev[i] = new double*[N_p+1];
u_prev_prev[i] = new double*[N_p+1];
for(int j = 0; j < N_p+1; j++) {
u[i][j] = new double[N_p+1];
u_prev[i][j] = new double[N_p+1];
u_prev_prev[i][j] = new double[N_p+1];
for(int k = 0; k < N_p+1; k++) {
u[i][j][k] = 0.0;
u_prev[i][j][k] = 0.0;
u_prev_prev[i][j][k] = 0.0;
}
}
}
但我的朋友谁已经做了这个任务告诉我将有问题,当我需要发送或收到消息/从其他进程(因为我需要发送完整的层大小为(N + 1)^ 2这些都是垂直于Y轴的,并且将这些阵列放置在内存中将会是一个大问题
同样我们并不需要全部N + 1点在Y轴上,正如我先做的那样,只是p其中每个过程都可以。由于内存问题是非常实际的(最大N在一些测试将在1536左右。我们给出了测试资源非常少)
于是,他提出了这样做的:(他垂直于X轴做并行片,而不是Y轴从我和记数到N-1和不从到ň作为我来说,这不是什么大问题,但是这个代码是某种魔术对我来说,我不明白它完全反正。)
float* buffer = new float[N * N * (N/s) * 3];
float ***u;
for (int i = left; i < right; ++i) {
u[i] = new float*[N];
for (int j = 0; j < N; ++j) {
u[i][j] = buffer + (i - left)*N*N + j*N;
}
}
所以我尝试在我的大脑着火时做类比,并且很快就会爆炸:
float* buffer = new float[(N+1) * p * (N+1) * 3];
float ***u;
for (int i = 0; i <= N; ++i) {
u[i] = new float*[p];
//p = right-left+1
for (int j = left; j <= right; ++j) {
u[i][j] = buffer + ???; //SOS
}
}
请有人试着理解这种方法,并解释什么来代替“???”。或者其他更好的解决方案。
而且我的队友告诉记者,这将是可以简单地写U [i] [j] [k]的代码但是我不知道我是否有ķ指数与这样definiton是否我需要改变我所有的计算语法。
对不起,有这么大的解释和问题。我真的不想自己理解它,并很快解决它。但现在我被卡住了。
同时粘贴一个立方体的小图像和红色的标记图层,用于一些简单的vizualization。
我宁愿封装这样的问题在课堂上(OOP吧?)。理解起来更容易,可重复使用,开销很小。任何类型的3D矩阵是:
template<typename T>
class Matrix {
private:
int _dimX, _dimY, _dimZ;
T *_storage;
public:
inline Matrix(int dimX, int dimY, int dimZ) {
_dimX = dimX; _dimY = dimY; _dimZ = dimZ;
_storage = new T[_dimX * _dimY * _dimZ];
}
inline ~Matrix() { delete _storage; }
inline T* getStorage() const { return _storage; }
inline T &operator()(int x, int y, int z) {
return _storage[x * _dimX * _dimY + y * _dimY + z];
}
};
,并用它:
#include <iostream>
using std::cout;
using std::endl;
int main() {
int xlen = 10, ylen = 5, zlen = 2;
// Creating matrix of doubles
Matrix<double> matrix(xlen, ylen, zlen);
// Filling using contiguous memory array (to export)
double *d = matrix.getStorage();
int count = 0;
for (int i = 0; i < xlen * ylen * zlen; i++)
*d++ = ++count; // same as d[i] = ++count;
// Using with indexes
cout << "matrix(1,0,0) = " << matrix(1, 0, 0) << endl; // prints 51
matrix(1, 0, 0) = 34;
cout << "matrix(1,0,0) = " << matrix(1, 0, 0) << endl; // prints 34
matrix(1, 0, 0)++;
cout << "matrix(1,0,0) = " << matrix(1, 0, 0) << endl; // prints 35
return 0;
}
为什么你使用'operator()'进行索引而不是'[...]'?它违背了每个C++约定(和其他语言),看起来像一个正常的函数调用。 –
因为operator []只能带一个参数。我没有想太多,但也许可以使用operator [],但是现在我想到的每个解决方案都比operator()更复杂和/或更慢。 – WPomier
啊 - 好点。我可能只会使用返回'T&'的方法 - 但它基本上与您的操作符重载相同。差异是学术的。 :)感谢您的代码。 –
http://www.boost.org/doc/libs/1_61_0/libs/multi_array/doc/user。 html –
在你发布的第二个代码中,你没有足够的“层次”(不知道别的怎么说)。它应该是:
float ***u; u = new float**[N + 1];
等 –对于访问您的单维数组,假设您的大小是x = 2,y = 2和z = 2。访问变成:[(i * y * z)+(j * y) + k]。 –