大一的时候在线性代数课程里学过,要选择列中最大的数作为pivot,目的是为了减少计算中产生的误差,昨晚自己写了一遍代码,发现果然如此。实践一下,更有助于学习!
测试数据:
A:
1.00 2.00 1.00 4.00
2.00 0.00 4.00 3.00
4.00 2.00 2.00 1.00
-3.00 1.00 3.00 2.00B:
13.00
28.00
20.00
6.00C=B/A:
3.00
-1.00
4.00
2.00D=A*B:
113.00
124.00
154.00
61.00
#include <cassert> #include <cstring> #include <cmath> #include <cstdio> class Matrix{ private: int rows, cols; float* data; public: int getRows()const{ return rows; } int getColumns()const{ return cols; } Matrix(): rows(0), cols(0), data(0){} Matrix(int r, int c){ rows = r, cols = c; data = new float[r*c]; this->zeros(); } Matrix(int r, int c, float** d){ rows = r, cols = c; data = new float[r*c]; memcpy(data, d, sizeof(float)*r*c); } Matrix(const Matrix& m){ rows = m.rows, cols = m.cols; data = new float[rows*cols]; memcpy(data, m.data, sizeof(float)*rows*cols); } ~Matrix(){ delete data; } void set(int r, int c, float val){ if(r*cols+c>=rows*cols) throw "Out of boundary!"; data[r*cols+c] = val; } float get(int r, int c) const { return data[r*cols+c]; } void zeros(){ memset(data, 0, sizeof(float)*rows*cols); } Matrix& copy(const Matrix& m, int r, int c){ return copy(m, 0, 0, m.rows, m.cols, r, c); } Matrix& copy(const Matrix& m, int r, int c, int nr, int nc, int r0, int c0){ for(int i=0; i<nr; i++) for(int j=0; j<nc; j++) this->set(i+r0, j+c0, m.get(i+r, j+c)); return *this; } Matrix& swapRows(int r1, int r2){ Matrix C(1, this->cols); C.copy(*this, r1, 0, 1, this->cols, 0, 0); this->copy(*this, r2, 0, 1, this->cols, r1, 0) .copy(C, 0, 0, 1, this->cols, r2, 0); } Matrix& operator = (const Matrix& m){ delete data; this->rows = m.rows, this->cols = m.cols; data = new float[this->rows*this->cols]; memcpy(data, m.data, sizeof(float)*rows*cols); return *this; } Matrix operator * (const Matrix& m){ Matrix res(this->rows, m.cols); if(this->cols!=m.rows) throw "Matrix failed to multiply!"; for(int i=0; i<res.rows; i++) for(int j=0; j<res.cols; j++) for(int k=0; k<this->cols; k++) res.data[i*res.cols+j] += this->get(i, k) * m.get(k, j); return res; } Matrix operator / (const Matrix& A){ /* Gaussian Elimination * AX=B X=B/A */ if(A.rows!=A.cols || this->cols!=1) throw "Invalid matrix A or B!"; Matrix X(A.cols, 1), &B=*this, Aug(A.rows, A.cols+1); /* Make a augumented matrix */ Aug.copy(A, 0, 0).copy(B, 0, A.cols); /* sort the pivots */ for(int i=0; i<Aug.rows; i++){ int maxi = i; for(int j=i+1; j<Aug.rows; j++) if(fabs(Aug.get(j, i)) > fabs(Aug.get(maxi, i))) maxi = j; if(maxi!=i) Aug.swapRows(i, maxi); if(Aug.get(i, i)==0) throw "Singular matrix!"; for(int k=i+1; k<Aug.rows; k++){ float m=Aug.get(k, i) / Aug.get(i, i); for(int v=0; v<Aug.cols; v++) Aug.set(k, v, Aug.get(k, v) - m*Aug.get(i, v)); } } /* Back Substitution */ int z = X.rows - 1; X.set(z,0, Aug.get(z, X.rows) / Aug.get(z, z)); for(z--; z>=0; z--){ float m = 0; for(int p=z+1; p<X.rows; p++) m += Aug.get(z, p) * X.get(p, 0); X.set(z, 0, (Aug.get(z, X.rows) - m) / Aug.get(z, z)); } return X; } void print(){ for(int i=0; i<rows; i++){ for(int j=0; j<cols-1; j++) printf("%.2f ", data[i*cols+j]); printf("%.2f\n", data[i*cols+cols-1]); } printf("\n"); } }; int main(int argc, char **argv) { float a[4][4]={ 1.0, 2.0, 1.0, 4.0, 2.0, 0.0, 4.0, 3.0, 4.0, 2.0, 2.0, 1.0, -3.0, 1.0, 3.0, 2.0 }; float b[4] = {13.0, 28.0, 20.0, 6.0 }; Matrix A(4, 4, (float**)a), B(4, 1, (float**)b); puts("A:"); A.print(); puts("B:"); B.print(); Matrix C = B / A; puts("C=B/A:"); C.print(); Matrix D = A * B; puts("D=A*B:"); D.print(); return 0; }
我用matlab计算c=b/a计算不出来 c=b\a计算结果为
>> a=[1,2,1,4;2,0,4,3;4,2,2,1;-3,1,3,2];
>> b=[13;28;20;6];
>> d=a*b
d =
113
124
154
61
>> c=b\a
c =
0.0943 0.0518 0.1317 0.1210
>> c=b/a
??? Error using ==> mrdivide
Matrix dimensions must agree.
呃。。。我本来也想用 \ 运算符的,但是据说C++里不能重载这个运算符,所以我才用了 / 。其实就是求解线性方程组AX=B。
最近都Matrix了,可见行列式在研究上的意义了…
嗯,用Matrix能够很方便地表示一些数据嘛。个人觉得,其实就是一个二位数组。矩阵这名起得好听了~