Clase de matriz C ++
En C, si quisiera crear una estructura matricial, usaría:
struct matrix {
int col, row;
double data[1]; // I want the matrix entries stored
// right after this struct
}
Entonces puedo asignarlo con
matrix* allocate_matrix(int row, int col) {
matrix* m = malloc(sizeof(matrix) + sizeof(double) * (row * col - 1));
m->row = row; m->col = col;
return m;
}
¿Ahora hago el equivalente en C++?
EDITAR:
Quiero saber la forma canónica de implementar una clase matricial en C++.
nota bene.
Esta respuesta tiene 20 votos a favor ahora, pero no pretende ser un respaldo destd::valarray
.
En mi experiencia, es mejor invertir el tiempo instalando y aprendiendo a usar una biblioteca matemática completa como Eigen . Valarray tiene menos funciones que la competencia, pero no es más eficiente ni particularmente más fácil de usar.
Si solo necesita un poco de álgebra lineal y está decidido a agregar algo a su cadena de herramientas, entonces tal vez valarray
sea adecuado. Pero quedarse estancado sin poder expresar la solución matemáticamente correcta a su problema es una posición muy mala. Las matemáticas son implacables e implacables. Utilice la herramienta adecuada para el trabajo.
La biblioteca estándar proporciona std::valarray<double>
. std::vector<>
, sugerido por algunos otros aquí, está pensado como un contenedor de uso general para objetos. valarray
, menos conocido porque es más especializado (sin utilizar "especializado" como término C++), tiene varias ventajas:
- No asigna espacio extra. A
vector
se redondea a la potencia de dos más cercana al asignar, por lo que puede cambiar su tamaño sin reasignarlo cada vez. (Aún puedes cambiar el tamaño de unvalarray
; sigue siendo tan caro comorealloc()
). - Puede dividirlo para acceder fácilmente a filas y columnas.
- Los operadores aritméticos funcionan como era de esperar.
Por supuesto, la ventaja sobre usar C es que no es necesario administrar la memoria. Las dimensiones pueden residir en la pila o en un objeto de corte.
std::valarray<double> matrix( row * col ); // no more, no less, than a matrix
matrix[ std::slice( 2, col, row ) ] = pi; // set third column to pi
matrix[ std::slice( 3*row, row, 1 ) ] = e; // set fourth row to e
C++ es principalmente un superconjunto de C. Puedes continuar haciendo lo que estabas haciendo.
Dicho esto, en C++, lo que debes hacer es definir una clase Matrix adecuada que administre su propia memoria. Podría, por ejemplo std::vector
, estar respaldado por un internal y podría anular operator[]
o operator()
indexar el vector adecuadamente (por ejemplo, consulte: ¿ Cómo creo un operador de subíndice para una clase Matrix? de las preguntas frecuentes de C++).
Para empezar:
class Matrix
{
public:
Matrix(size_t rows, size_t cols);
double& operator()(size_t i, size_t j);
double operator()(size_t i, size_t j) const;
private:
size_t mRows;
size_t mCols;
std::vector<double> mData;
};
Matrix::Matrix(size_t rows, size_t cols)
: mRows(rows),
mCols(cols),
mData(rows * cols)
{
}
double& Matrix::operator()(size_t i, size_t j)
{
return mData[i * mCols + j];
}
double Matrix::operator()(size_t i, size_t j) const
{
return mData[i * mCols + j];
}
(Tenga en cuenta que lo anterior no realiza ninguna verificación de límites, y lo dejo como ejercicio para crear una plantilla para que funcione para otras cosas además de double
.)
Podrías hacerlo de esa manera. La única diferencia es que necesitarías convertir el resultado desde malloc
.
Más bien, usaría a vector
, ya sea como una matriz 1D con indexación calculada o como un vector incrustado. (El primero coincide mejor con su código).
Por ejemplo:
template <typename T> // often, they are templates
struct matrix
{
// should probably be hidden away, and the class would
// provide `at` and `operator()` for access
int col, row;
std::vector<T> data;
matrix(int columns, int rows) :
col(columns), row(rows),
data(col * row)
{}
}
matrix m(4, 4);
m.data[1 + 1 * 4] = /* ... */;
O:
template <typename T>
struct matrix
{
int col, row;
std::vector<std::vector<T> > data;
matrix(int columns, int rows) :
col(columns), row(rows),
data(col, std::vector(row))
{}
}
matrix m(4, 4);
m.data[1][1] = /* ... */;
Pero estos son sólo ejemplos. Querrás hacer una clase completa; Si desea obtener más consejos sobre eso, edite su pregunta y aclare que le gustaría conocer la forma canónica de implementar clases matriciales.
Hay clases matriciales preexistentes. Mi favorito es el de boost, UBLAS .