C++实现伽罗华域生成及四则运算(二)
目录
- 一、数的次幂
- 二、矩阵数乘
- 三、矩阵转置
- 四、方阵次幂
- 五、行列式
- 六、伴随矩阵
- 七、逆矩阵
- 八、测试用例
上一篇文章介绍了用C++实现伽罗华域 G F ( 2 n ) GF(2^n) GF(2n)生成及四则运算,本篇接上,继续探索,扩展了数的次幂、矩阵数乘、方阵次幂、求行列式、求伴随矩阵、逆矩阵的函数。
一、数的次幂
这比较简单,就是不断乘,代码如下:
/*次幂*/
template<uint8_t n>
uint16_t GFM<n>::gfPow(uint16_t a, uint16_t m) {if (a == 0) {if (m >= 0) return 0;else throw TypeException("除0错误");} else if (a == 1) return 1;uint16_t res = 1;if (m == 0) return 1;else { //正常乘,m的类型使得其不可能是负值for (int16_t i = 0; i < m % (this->N - 1); i++) { //定理a^(N-1)=1res = this->multi(res, a);}}// else { //m < 0,倒数// for (int16_t i = 0; i < (0 - m) % (this->N - 1); i++) { // 计算分母// res = this->multi(res, a);// }// res = this->adver(res); //=1/res// } //end of ifreturn res;
}
当然符号优先级也得改,还有二元运算的封装函数:
/*二元操作符优先级*/
template<uint8_t n>
int8_t GFM<n>::operatorOrder(char opt) {if (opt == '#') return 0; //自定义的用于标志运算符栈结束if (opt == '+' || opt == '-') return 1; //加减if (opt == '*' || opt == '/') return 2; //乘除if (opt == '^') return 3; //次幂if (opt == '(' || opt == ')') return 4;return -1;
}/*二元运算操作函数*/
template<uint8_t n>
uint16_t GFM<n>::calculate(uint16_t a, uint16_t b, char opt) {if (opt == '+' || opt == '-') return a ^ b;else if (opt == '*') return this->multi(a,b);else if (opt == '/') return this->multi(a, this->adver(b));else if (opt == '^') return this->gfPow(a, b);else throw TypeException("运算符错误");return 0;
}
二、矩阵数乘
/*矩阵数乘*/
template<uint8_t n>
void GFM<n>::matrixNumMulti(uint16_t* res, uint16_t* A, uint16_t r, uint16_t c, uint16_t m) {for (uint16_t i = 0; i < r; i++) {for (uint16_t j = 0; j < c; j++) {res[i*c+j] = this->multi(A[i*c+j],m);}}
}
三、矩阵转置
/*使矩阵转置,从r行c列变成c行r列*/
template<uint8_t n>
void GFM<n>::matrixT(uint16_t* res, uint16_t* A, uint16_t r, uint16_t c) {if (r == 0 || c == 0) throw TypeException("转置矩阵行列错误");for (uint16_t i = 0; i < r; i++) {for (uint16_t j = 0; j < c; j++) {//第i行j列变为第j行第i列res[j*r+i] = A[i*c+j];}}
}
四、方阵次幂
/*方阵次幂,A是r阶,求A^m*/
template<uint8_t n>
void GFM<n>::matrixPow(uint16_t* res, uint16_t* A, uint16_t r, uint16_t m) {if (m == 0) throw TypeException("矩阵幂次出错");uint16_t* temp = (uint16_t*)malloc(sizeof(uint16_t) * r * r); //建立缓存矩阵memcpy(res, A, sizeof(uint16_t) * r * r);for (uint16_t i = 1; i < m; i++) {memcpy(temp, res, sizeof(uint16_t) * r * r);this->matrixMulti(res, temp, r, r, A, r, r);}free(temp); //释放缓存
}
五、行列式
使用代数余子式法,将除数不断减小以嵌套计算
/*方阵行列式,r是阶数
代数余子式法
*/
template<uint8_t n>
uint16_t GFM<n>::delta(uint16_t* A, uint16_t r) {if (r == 0) throw TypeException("矩阵阶数出错");if (r == 1) return A[0];if (r == 2) return this->multi(A[0],A[3]) ^ this->multi(A[1],A[2]);// 按第0行展开代数余子式uint16_t* B = (uint16_t*)malloc(sizeof(uint16_t) * (r-1) * (r-1));uint16_t res = 0;for (uint16_t omit = 0; omit < r; omit++) { //指定列号,求指定列的代数余子式for (uint16_t i = 1, k = 0; i < r; i++) { //从第1行开始读取,写入B[k]for (uint16_t j = 0; j < r; j++) { //逐列读取if (j == omit) continue; //跳过指定的列B[k++] = A[i*r+j];}}res ^= this->multi(A[omit],delta(B, r-1)); //按A的第0行代数余子式展开 }free(B); //释放内存return res;
}
六、伴随矩阵
/*求方阵A的伴随矩阵,r是阶数*/
template<uint8_t n>
void GFM<n>::matrixAsterisk(uint16_t* res, uint16_t* A, uint16_t r) {if (r <= 1) throw TypeException("没有伴随矩阵");uint16_t* temp = (uint16_t*)malloc(sizeof(uint16_t) * r * r);uint16_t* B = (uint16_t*)malloc(sizeof(uint16_t) * (r-1) * (r-1));for (uint16_t omit_r = 0; omit_r < r; omit_r++) { //指定行号,求指定行的代数余子式for (uint16_t omit_c = 0; omit_c < r; omit_c++) { //指定列号,求指定位置的代数余子式//开始写入子方阵for (uint16_t i = 0, k = 0; i < r; i++) { //从第0行开始读取,写入B[k]if (i == omit_r) continue; //省略本行for (uint16_t j = 0; j < r; j++) { //逐列读取if (j == omit_c) continue; //省略本列B[k++] = A[i*r+j];}}//求对应余子矩阵行列式的值temp[omit_r*r+omit_c] = this->delta(B, r-1);
// cout << "temp[omit_r*r+omit_c]=" << temp[omit_r*r+omit_c] << endl;}} //end of forfree(B); //释放内存this->matrixT(res, temp, r, r); //求转置矩阵free(temp); //释放内存
}
七、逆矩阵
/*求方阵的逆矩阵,r是阶数*/
template<uint8_t n>
void GFM<n>::matrixAdver(uint16_t* res, uint16_t* A, uint16_t r) {uint16_t del = this->delta(A, r);
cout << "|A|=" << del << " 1/|A|=" << this->adver(del) << endl; if (del == 0) throw TypeException("无逆矩阵,因为行列式为0");this->matrixAsterisk(res, A, r);this->matrixNumMulti(res, res, r, r, this->adver(del)); //A^-1 = A*/|A|
}
八、测试用例
int main(int argc, char*argvs[]) {//测试矩阵数乘// GFM<8> gf8;// uint16_t f[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1};// gf8.matrixNumMulti(f, f, 4, 4, 0xe2);// for (int i = 0; i < 4; i++) {// for (int j = 0; j < 4; j++){// cout << hex << f[i*4+j] << " ";// }// cout << endl;// }//测试矩阵次幂// GFM<8> gf8;// uint16_t a[16] = {2,3,1,1,1,2,3,1,1,1,2,3,3,1,1,2};// uint16_t res[16];// gf8.matrixPow(res, a, 4, 4);// for (int i = 0; i < 4; i++) {// for (int j = 0; j < 4; j++){// cout << hex << res[i*4+j] << " ";// }// cout << endl;// }//测试方阵行列式// GFM<8> gf8;// uint16_t a[9] = {2,3,1, 1,2,3, 3,1,2};// cout << gf8.delta(a, 3) << endl;// uint16_t b[16] = {0x7,0x8,0x9,0xa,0xa,0x7,0x8,0x9,0x9,0xa,0x7,0x8,0x8,0x9,0xa,0x7};// cout << gf8.delta(b, 4) << endl;// uint16_t c[16] = {0xe,0xb,0xd,0x9, 0xb,0xd,0x9,0xe, 0xd,0x9,0xe,0xb, 0x9,0xe,0xb,0xd};// cout << gf8.delta(c, 4) << endl;// uint16_t d[25] = {0x5,0x0,0x3,0x2,0x4, 0x4,0x5,0x0,0x3,0x2, 0x2,0x4,0x5,0x0,0x3, 0x3,0x2,0x4,0x5,0x0, 0x0,0x3,0x2,0x4,0x5};// cout << gf8.delta(d, 5) << endl;//测试矩阵转置// GFM<8> gf8;// uint16_t a[16] = {2,3,1,1, 1,2,3,1, 1,1,2,3, 3,1,1,2};// uint16_t res[16];// cout << "原矩阵:" << endl;// for (int i = 0; i < 2; i++) {// for (int j = 0; j < 8; j++){// cout << hex << a[i*8+j] << " ";// }// cout << endl;// }// cout << "转置矩阵:" << endl;// gf8.matrixT(res, a, 2, 8);// for (int i = 0; i < 8; i++) {// for (int j = 0; j < 2; j++){// cout << hex << res[i*2+j] << " ";// }// cout << endl;// }//测试伴随矩阵及逆矩阵GFM<8> gf8;// gf8.toString();uint16_t a[16] = {2,4,1,1, 1,2,3,1, 1,1,2,3, 3,1,1,2};uint16_t res[16];gf8.matrixAsterisk(res, a, 4);cout << "伴随矩阵:" << endl;for (int i = 0; i < 4; i++) {for (int j = 0; j < 4; j++){cout << hex << res[i*4+j] << " ";}cout << endl;}cout << "逆矩阵:" << endl;gf8.matrixAdver(res, a, 4);for (int i = 0; i < 4; i++) {for (int j = 0; j < 4; j++){cout << hex << res[i*4+j] << " ";}cout << endl;}cout << "验证:" << endl;uint16_t q[16];memcpy(q, res, sizeof(uint16_t)*16);gf8.matrixMulti(res, q, 4, 4, a, 4, 4);for (int i = 0; i < 4; i++) {for (int j = 0; j < 4; j++){cout << hex << setw(2) << res[i*4+j] << " ";}cout << endl;}//命令行计算器实现部分// GFM<8> gf8;string s;while(true) {cout << "请输入表达式:" << flush;getline(cin,s);try {cout << hex << gf8.calc(s.c_str()) << endl;} catch (TypeException e) { //自定义异常cout << e.what() << endl;} catch (std::invalid_argument e) { //stoi异常cout << e.what() << endl;}}return 0;
}