我正在尝试用 Java 重写代码,以求解一组对浮点数进行高斯消元的线性方程,以处理以素数为模的方程。问题是它不起作用,我无法弄清楚出了什么问题。它似乎适用于小型方程组,但不适用于大型方程组,这使得调试变得困难。
我的算法取第一行,通过找到第一个元素的倒数对其进行归一化,并将行中的每个元素乘以这个倒数。然后它从其他行中减去这一行足够的次数以使它们的第一个元素为零。在下一次迭代中,它转到下一行并执行相同的过程,直到第 i 行的枢轴元素在第 i 列中。最后,它从前几行中减去每一行,以使每一列只有一个非零元素(最后一个除外)。(到目前为止,我使用双打,这不是必需的,但这应该不是问题)。这是我的代码:
// Transforms A so that the leftmost square matrix has at most one 1 per row,
// and no other nonzero elements.
// O(n^3)
public static void gauss(int[][] A, int num_columns) {
int n = A.length;
int m = A[0].length;
for (int i = 0; i < num_columns; i++) {
// Finding row with nonzero element at column i, swap this to row i
for(int k = i; k < num_columns; k++){
if(A[k][i] != 0){
int t[] = A[i];
A[i] = A[k];
A[k] = t;
}
}
// Normalize the i-th row.
int inverse = (int)inverse((long)A[i][i], prime);
for (int k = i ; k < m; k++) A[i][k] = (A[i][k]*inverse) % prime;
// Combine the i-th row with the following rows.
for (int j = 0; j < n; j++) {
if(j == i) continue;
int c = A[j][i];
A[j][i] = 0;
for (int k = i + 1; k < m; k++){
A[j][k] = (A[j][k] - c * A[i][k] + c * prime) % prime;
}
}
}
}
public static void gauss(int[][] A) {
gauss(A, Math.min(A.length, A[0].length));
}
public static long gcd(long a, long b){
if(a < b){
long temp = a;
a = b;
b = temp;
}
if(b == 0) return a;
return gcd(b, a % b);
}
public static Pair ext_euclid(long a, long b){
if(a < b){
Pair r = ext_euclid(b,a);
return new Pair(r.second, r.first);
}
if(b == 0) return new Pair(1, 0);
long q = a / b;
long rem = a - b * q;
Pair r = ext_euclid(b, rem);
Pair ret = new Pair(r.second, r.first - q * r.second);
return ret;
}
public static long inverse(long num, long modulo){
num = num%modulo;
Pair p = ext_euclid(num, modulo);
long ret = p.first;
if(ret < 0) return (modulo + ret) % modulo;
return ret % modulo;
}
static class Pair{
public long first;
public long second;
public Pair(long frst, long scnd){
first = frst;
second = scnd;
}
}
这适用于小例子(mod 29):
matrix = {{1.0, 1.0, 1.0, 1.0}, {1.0, 2.0, 1.0, 2.0},{1.0, 0.0, 0.0‚ 3.0}};
answer= {{1.0, 0.0, 0.0, 0.0},{0.0, 1.0, 0.0, 1.0}, {0.0, 0.0, 1.0, 0.0}};
哪个是正确的(第一个变量 = 0,第二个 = 1.0,第三个 = 0),可以通过 WolframAlpha 检查 0*k^0 + 1*k^1 + 0*k^2 对于 k = 1..3。
对于这个例子,有 10 个变量,方程 a*k^0 + b*k^1 + c*k^2... (mod 29) for k = 1..11,我有这个矩阵:
1 1 1 1 1 1 1 1 1 1 1 8
1 2 4 8 16 3 6 12 24 19 9 5
1 3 9 27 23 11 4 12 7 21 5 12
1 4 16 6 24 9 7 28 25 13 23 12
1 5 25 9 16 22 23 28 24 4 20 15
1 6 7 13 20 4 24 28 23 22 16 0
1 7 20 24 23 16 25 1 7 20 24 5
1 8 6 19 7 27 13 17 20 15 4 1
1 9 23 4 7 5 16 28 20 6 7 18
1 10 13 14 24 8 22 17 25 18 7 20
1 11 5 26 25 14 9 12 16 7 7 8
使用我的算法,我得到了答案:
1 0 0 0 0 0 0 0 0 0 0 18
0 1 0 0 0 0 0 0 0 0 0 8
0 0 1 0 0 0 0 0 0 0 0 15
0 0 0 1 0 0 0 0 0 0 0 11
0 0 0 0 1 0 0 0 0 0 0 28
0 0 0 0 0 1 0 0 0 0 0 27
0 0 0 0 0 0 1 0 0 0 0 7
0 0 0 0 0 0 0 1 0 0 0 21
0 0 0 0 0 0 0 0 1 0 0 9
0 0 0 0 0 0 0 0 0 1 0 24
0 0 0 0 0 0 0 0 0 0 1 14
但这是错误的!(可以用 WolframAlpha 检查)。正确答案应该是 (abc ...) = (8 13 9 13 4 27 18 10 12 24 15)。
有人能看出我的错误吗?还是我误解了如何做 Gauss mod p?