joeslow
asked on
Dynamic multidimensional array of doubles
Hi,
I need to declare a large three dimensional array of doubles. If I do this:
double arr[200][200][400];
I get a runtime stack overflow error.
So I need to create it dynamically like
double (*arr)[200][400] = new double[200][200][400];
But now I don't want the sizes to be predefined. How can I declare a 3D array of doubles at runtime, use it (assign values to it), and clean up when finished?
Thank you,
Joe
I need to declare a large three dimensional array of doubles. If I do this:
double arr[200][200][400];
I get a runtime stack overflow error.
So I need to create it dynamically like
double (*arr)[200][400] = new double[200][200][400];
But now I don't want the sizes to be predefined. How can I declare a 3D array of doubles at runtime, use it (assign values to it), and clean up when finished?
Thank you,
Joe
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
The ugly truth is that neither C or C++ have a varible array dimension feature, said feature has been in other languages like FORTRAN for 30+ years now.
You can cobble up something with macros, but it won't be pretty.
Alternatives include: doing the variable array stuff in another language (FORTRAN, Pascal, Java), or use a large fixed size array. With memory going for 10 cents a megabyte, this is often the fastest and cheapest option.
You can cobble up something with macros, but it won't be pretty.
Alternatives include: doing the variable array stuff in another language (FORTRAN, Pascal, Java), or use a large fixed size array. With memory going for 10 cents a megabyte, this is often the fastest and cheapest option.
You can use std::vector<double>.
e.g.:
--------8<--------
#include <iostream>
#include <vector>
#include <iomanip>
typedef std::vector<double> DoubleV;
typedef std::vector<DoubleV> DoubleVV; // 2D "array" of doubles
typedef std::vector<DoubleVV> DoubleVVV; // "Array" of 2D "array" of doubles
int main()
{
DoubleVVV dVVV(10);
double value = 0.0;
for (int i = 0;i < 10;i++) {
DoubleVV& dVV = dVVV[i];
dVV.resize(100);
for (int x = 0;x < 100;x++) {
DoubleV& dV = dVV[x];
dV.resize(100);
for (int y = 0;y < 100;y++)
dV[y] = value += 1.00001;
}
}
{
int i,x,y;
std::cout << "Choose an array 0..9: ";std::cin >> i;
std::cout << "Choose an x-coord 0..99: ";std::cin >> x;
std::cout << "Choose a y-coord 0..99: ";std::cin >> y;
std::cout << std::fixed << std::setprecision(5);
if (i >= 0 && i < 10 && x >= 0 && x < 100 && y >= 0 && y < 100)
std::cout << "Value is: " << dVVV[i][x][y] << '\n';
}
}
--------8<--------
e.g.:
--------8<--------
#include <iostream>
#include <vector>
#include <iomanip>
typedef std::vector<double> DoubleV;
typedef std::vector<DoubleV> DoubleVV; // 2D "array" of doubles
typedef std::vector<DoubleVV> DoubleVVV; // "Array" of 2D "array" of doubles
int main()
{
DoubleVVV dVVV(10);
double value = 0.0;
for (int i = 0;i < 10;i++) {
DoubleVV& dVV = dVVV[i];
dVV.resize(100);
for (int x = 0;x < 100;x++) {
DoubleV& dV = dVV[x];
dV.resize(100);
for (int y = 0;y < 100;y++)
dV[y] = value += 1.00001;
}
}
{
int i,x,y;
std::cout << "Choose an array 0..9: ";std::cin >> i;
std::cout << "Choose an x-coord 0..99: ";std::cin >> x;
std::cout << "Choose a y-coord 0..99: ";std::cin >> y;
std::cout << std::fixed << std::setprecision(5);
if (i >= 0 && i < 10 && x >= 0 && x < 100 && y >= 0 && y < 100)
std::cout << "Value is: " << dVVV[i][x][y] << '\n';
}
}
--------8<--------
> Alternatives include: doing the variable array stuff in another language (FORTRAN, Pascal, Java),
I think that is NEVER a good alternative. Object Oriented languages was designed to permit you design YOU OWN variables types. Never a languages will have all variable types you want because every user has a different requirement.
So, when you don't have the type you want, design it.
Some examples of not pre-made types:
- complex numbers
- fractional numbers
- huge integers
- huge floating point numbers
- 3 dimensional dinamic arrays
.....etcetera
I think that is NEVER a good alternative. Object Oriented languages was designed to permit you design YOU OWN variables types. Never a languages will have all variable types you want because every user has a different requirement.
So, when you don't have the type you want, design it.
Some examples of not pre-made types:
- complex numbers
- fractional numbers
- huge integers
- huge floating point numbers
- 3 dimensional dinamic arrays
.....etcetera
C, and so C++, certainly do have support for variable arrays. The syntax doesn't allow you to create them directly, but they can be created with a little work. They can then be used with the built in syntax. Suppose your three dimensions are stored in variables d1, d2 and d3. You would then dynamically construct the array as follows:
double **mx;
mx=new double **[d1];
for(int i=0; i<d1; ++i)
{ mx[i]=new double *[d2];
for(int j=0; j<d2; ++j)mx[i][j]=new double[d3];
}
The items in the matrix can now be accessed with the standard array syntax, e.g.:
mx[1][5][2]=0.00;
freeing the dynamic memory requires the reverse process.
double **mx;
mx=new double **[d1];
for(int i=0; i<d1; ++i)
{ mx[i]=new double *[d2];
for(int j=0; j<d2; ++j)mx[i][j]=new double[d3];
}
The items in the matrix can now be accessed with the standard array syntax, e.g.:
mx[1][5][2]=0.00;
freeing the dynamic memory requires the reverse process.
ASKER
Hi,
Thanks to all who answered. When I first asked this question I didn't realize what a problem it would be. Anyway, I liked Jaime's approach because in the end, I need to pass the array to a MATLab dll so the vector stuff won't work in my case - I guess I should have mentioned that. Anyway, now I can use the data class member as the array I pass.
Thanks again,
Joe
Thanks to all who answered. When I first asked this question I didn't realize what a problem it would be. Anyway, I liked Jaime's approach because in the end, I need to pass the array to a MATLab dll so the vector stuff won't work in my case - I guess I should have mentioned that. Anyway, now I can use the data class member as the array I pass.
Thanks again,
Joe
> I need to pass the array to a MATLab dll so the vector stuff won't work in my case
You can pass arrays of doubles with the vector approach
// External function handles an array of doubles
extern "C" void f(double values[],size_t count);
// Call it with this.
f(&dVVV[i][x][0],dVVV[i][x ].size());
You can pass arrays of doubles with the vector approach
// External function handles an array of doubles
extern "C" void f(double values[],size_t count);
// Call it with this.
f(&dVVV[i][x][0],dVVV[i][x
!>C, and so C++, certainly do have support for variable arrays.
!>The items in the matrix can now be accessed with the standard array syntax, e.g.:
!>mx[1][5][2]=0.00;
Pls explain how the compiler knows at run-time the dimensions of array mx, in order to correctly execute the above statement.
You also didnt mention this requires at least 50% extra memory, and double the memory reference time for the indirection, not to mention defeating any compiler's attempt at optimizing or allocating floating-point registers.
!>The items in the matrix can now be accessed with the standard array syntax, e.g.:
!>mx[1][5][2]=0.00;
Pls explain how the compiler knows at run-time the dimensions of array mx, in order to correctly execute the above statement.
You also didnt mention this requires at least 50% extra memory, and double the memory reference time for the indirection, not to mention defeating any compiler's attempt at optimizing or allocating floating-point registers.
> not to mention defeating any compiler's attempt at optimizing or allocating floating-point registers
Could you expand on this grg99?
Could you expand on this grg99?
ASKER
I found this explanation pretty interesting but I don't know if it's what you guys are talking about (scroll to bottom of page):
http://www.cs.wfu.edu/~torgerse/fftw_1.2/fftw_6.html#SEC31
Joe
http://www.cs.wfu.edu/~torgerse/fftw_1.2/fftw_6.html#SEC31
Joe
Interesting article!
As author says, you have to choose between easy to use/mantain and high performance. Not always high performace is better to easy to use and maintain.
As author says, you have to choose between easy to use/mantain and high performance. Not always high performace is better to easy to use and maintain.
>> not to mention defeating any compiler's attempt at optimizing or allocating floating-point registers
>Could you expand on this grg99?
Just that the compiler has no idea that what's pointed to by mx[1][1][1] is next to mx[1][1][2], so any loop that processes the whole arrray sequentially cant benefit from all the strength reductions of changing multiplies to adds. Likewise the compiler can't do any data-flow analysis on the F.P. data, so it has to assume the worst case, and it can't keep mx[a][b][c] in a F.P. register, because it could be aliased to mx[d][e][f]. And on a register-poor CPU like the x86, doing everything by indirection ties up one or more of the precious address-capable registers (really bad in 16-bit or segmented 32-bit modes, not quite so bad in 32-bit flat mode).
>Could you expand on this grg99?
Just that the compiler has no idea that what's pointed to by mx[1][1][1] is next to mx[1][1][2], so any loop that processes the whole arrray sequentially cant benefit from all the strength reductions of changing multiplies to adds. Likewise the compiler can't do any data-flow analysis on the F.P. data, so it has to assume the worst case, and it can't keep mx[a][b][c] in a F.P. register, because it could be aliased to mx[d][e][f]. And on a register-poor CPU like the x86, doing everything by indirection ties up one or more of the precious address-capable registers (really bad in 16-bit or segmented 32-bit modes, not quite so bad in 32-bit flat mode).
Alternatives include: doing the variable array stuff in another language (FORTRAN, Pascal, Java),
I think that is NEVER a good alternative. Object Oriented languages was designed to permit you design YOU OWN variables types.
... except a good 80% of the folks that would like to use variable-dim arrays are just average math and physics geeks, few of which are also capable enough to design a bulletproof multi-dim-array object.
... and C++ is particularly weak in giving one any traction in this particular area, since there's no syntax for overloading multiple subscripts.
You can do something kludgy like this, suggested by the C++ FAQ:
class Matrix {
public:
Matrix(unsigned rows, unsigned cols);
double& operator() (unsigned row, unsigned col);
double operator() (unsigned row, unsigned col) const;
...
~Matrix(); // Destructor
Matrix(const Matrix& m); // Copy constructor
Matrix& operator= (const Matrix& m); // Assignment operator
...
private:
unsigned rows_, cols_;
double* data_;
};
inline
Matrix::Matrix(unsigned rows, unsigned cols)
: rows_ (rows)
, cols_ (cols)
//data_ <--initialized below (after the 'if/throw' statement)
{
if (rows == 0 || cols == 0)
throw BadIndex("Matrix constructor has 0 size");
data_ = new double[rows * cols];
}
inline
Matrix::~Matrix()
{
delete[] data_;
}
inline
double& Matrix::operator() (unsigned row, unsigned col)
{
if (row >= rows_ || col >= cols_)
throw BadIndex("Matrix subscript out of bounds");
return data_[cols_*row + col];
}
inline
double Matrix::operator() (unsigned row, unsigned col) const
{
if (row >= rows_ || col >= cols_)
throw BadIndex("const Matrix subscript out of bounds");
return data_[cols_*row + col];
}
-------------------
You still need seperate classes for each number and type of dimension, but it's slightly better than nothing....
I think that is NEVER a good alternative. Object Oriented languages was designed to permit you design YOU OWN variables types.
... except a good 80% of the folks that would like to use variable-dim arrays are just average math and physics geeks, few of which are also capable enough to design a bulletproof multi-dim-array object.
... and C++ is particularly weak in giving one any traction in this particular area, since there's no syntax for overloading multiple subscripts.
You can do something kludgy like this, suggested by the C++ FAQ:
class Matrix {
public:
Matrix(unsigned rows, unsigned cols);
double& operator() (unsigned row, unsigned col);
double operator() (unsigned row, unsigned col) const;
...
~Matrix(); // Destructor
Matrix(const Matrix& m); // Copy constructor
Matrix& operator= (const Matrix& m); // Assignment operator
...
private:
unsigned rows_, cols_;
double* data_;
};
inline
Matrix::Matrix(unsigned rows, unsigned cols)
: rows_ (rows)
, cols_ (cols)
//data_ <--initialized below (after the 'if/throw' statement)
{
if (rows == 0 || cols == 0)
throw BadIndex("Matrix constructor has 0 size");
data_ = new double[rows * cols];
}
inline
Matrix::~Matrix()
{
delete[] data_;
}
inline
double& Matrix::operator() (unsigned row, unsigned col)
{
if (row >= rows_ || col >= cols_)
throw BadIndex("Matrix subscript out of bounds");
return data_[cols_*row + col];
}
inline
double Matrix::operator() (unsigned row, unsigned col) const
{
if (row >= rows_ || col >= cols_)
throw BadIndex("const Matrix subscript out of bounds");
return data_[cols_*row + col];
}
-------------------
You still need seperate classes for each number and type of dimension, but it's slightly better than nothing....
>... except a good 80% of the folks that would like to use variable-dim arrays are just average math and physics geeks,
> few of which are also capable enough to design a bulletproof multi-dim-array object.
That's why they are asking us
>... and C++ is particularly weak in giving one any traction in this particular area, since there's no syntax for overloading
> multiple subscripts
Overloading is one of many alternatives, created to facilitate reading of code. Personally I almost never use overloading. Using a object's functions has exactly the same effect. Overloaded operator is a function whos name is a symbol.
> few of which are also capable enough to design a bulletproof multi-dim-array object.
That's why they are asking us
>... and C++ is particularly weak in giving one any traction in this particular area, since there's no syntax for overloading
> multiple subscripts
Overloading is one of many alternatives, created to facilitate reading of code. Personally I almost never use overloading. Using a object's functions has exactly the same effect. Overloaded operator is a function whos name is a symbol.
Thanks for the clarification. I'm with you now. However, I wonder how realistic it is to question the efficiency of fetches like a_slow_array[i][j][k], when code that uses [][][] is unlikely (or at least oughtn't to be) in a loop anyhow. In a real world situation, I'd expect and expression like a_slow_array[i][j][k] to appear in something that was I/O bound and any loop processing to use iterators/pointers. I'd need to see what the profiler had to say, before.
> ... and C++ is particularly weak in giving one any traction in this particular area, since there's no syntax for overloading multiple subscripts.
You can, however, use adapter classes.
e.g. http://www.boost.org/libs/multi_array/doc/user.html
> ... and C++ is particularly weak in giving one any traction in this particular area, since there's no syntax for overloading multiple subscripts.
You can, however, use adapter classes.
e.g. http://www.boost.org/libs/multi_array/doc/user.html
Wow! I didnt know you could do THAT !
I do tremble a bit at the idea of templates generating templates....
I do tremble a bit at the idea of templates generating templates....
In which case, you'll either love or hate Modern C++ Design: Applied Generic and Design Patterns by Andrei Alexandrescu - see http://www.moderncppdesign.com/
Alexandrescu is the guy who came up with Loki, which I must confess that I'm struggling with (being a bear of little brain) but that I am strangely attracted to. It takes templates one step beyond.
Alexandrescu is the guy who came up with Loki, which I must confess that I'm struggling with (being a bear of little brain) but that I am strangely attracted to. It takes templates one step beyond.
Maybe this might help.
--Edward