上一篇文章介绍了用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)=1
res = 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 if
return 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 for
free(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;
}