Clase de matriz C ++

Resuelto anon asked hace 14 años • 0 respuestas

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++.

anon avatar Jan 16 '10 14:01 anon
Aceptado

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 valarraysea 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 vectorse 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 un valarray; sigue siendo tan caro como realloc()).
  • 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
Potatoswatter avatar Jan 16 '2010 08:01 Potatoswatter

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.)

jamesdlin avatar Jan 16 '2010 08:01 jamesdlin

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 .

GManNickG avatar Jan 16 '2010 08:01 GManNickG