最近在prealculus中了解了Cramers规则,并决定用Java编写一个算法来帮助我更好地理解它。
以下代码100%正确工作,但它不使用任何类型的for循环以更简单的方式执行它的工作。
问题:Java中是否有更优雅的Cramers规则实现?
我正在考虑制作一个基本的行列式方法,然后在我需要采用Dx,Dy和Dz的行列式时进行一些列交换。 (对于Dx,将第4列与原始矩阵的第1列交换,然后取决定因子并除以原始行列式。) 听起来不错?
public static void main(String[] args) {
int[][] matrix = new int[3][3];
matrix[0] = new int[] { 3, 5, -1, -2 };
matrix[1] = new int[] { 1, -4, 2, 13 };
matrix[2] = new int[] { 2, 4, 3, 1 };
int[] r = crame(matrix);
info("x: " + r[0] + ", y: " + r[1] + ", z: " + r[2]);
for(int i = 0; i < matrix.length; i++) {
int[] base = matrix[i];
if(check(base, r, base[3])) {
info("System " + (i+1) + " checks!");
} else {
info("System " + (i+1) + " fails check!");
}
}
}
public static int[] crame(int[][] m) {
int[] result;
if (m.length == 2) {
result = new int[2];
int D = (m[0][0] * m[1][1]) - (m[1][0] * m[0][1]);
int Dx = (m[0][2] * m[1][1]) - (m[1][2] * m[0][1]);
int Dy = (m[0][0] * m[1][2]) - (m[1][0] * m[0][2]);
result[0] = (int) (Dx / D);
result[1] = (int) (Dy / D);
} else if (m.length == 3) {
result = new int[3];
int D = (((m[0][2] * m[1][1] * m[0][2]) + (m[2][1] * m[1][2] * m[0][0]) + (m[2][2]
* m[1][0] * m[0][2])) - ((m[0][0] * m[1][1] * m[2][2])
+ (m[0][1] * m[1][2] * m[0][2]) + (m[0][2] * m[1][0] * m[2][1])));
int Dx = (((m[2][3] * m[1][1] * m[0][2]) + (m[2][1] * m[1][2] * m[0][3]) + (m[2][2]
* m[1][3] * m[0][1])) - ((m[0][3] * m[1][1] * m[2][2])
+ (m[0][1] * m[1][2] * m[2][3]) + (m[0][2] * m[1][3] * m[2][1])));
int Dy = (((m[2][0] * m[1][3] * m[0][2]) + (m[2][3] * m[1][2] * m[0][3]) + (m[2][2]
* m[1][0] * m[0][3])) - ((m[0][0] * m[1][3] * m[2][2])
+ (m[0][3] * m[1][2] * m[2][0]) + (m[0][2] * m[1][0] * m[2][3])));
int Dz = (((m[2][0] * m[1][1] * m[0][3]) + (m[2][1] * m[1][3] * m[0][0]) + (m[2][3]
* m[1][0] * m[0][1])) - ((m[0][0] * m[1][1] * m[2][3])
+ (m[0][1] * m[1][3] * m[2][0]) + (m[0][3] * m[1][0] * m[2][1])));
result[0] = (int) (Dx / D);
result[1] = (int) (Dy / D);
result[2] = (int) (Dz / D);
} else {
return new int[] {};
}
return result;
}
public static int product(int[] a, int[] b) {
int p = 0;
int[] fin = new int[(a.length -1)];
for(int x = 0; x < fin.length; x++) {
fin[x] = a[x] * b[x];
}
for (int f : fin) {
p += f;
}
return p;
}
public static boolean check(int[] a, int[] b, int z) {
return product(a, b) == z;
}
public static void info(String log) {
System.out.println(log);
}
我的问题涉及可用于仅使用Cramers规则求解方程组的特定算法,是否有更优雅的算法?该功能仅适用于方形矩阵。
这不是一个家庭作业,在HS之后我将学习CS并且我一直致力于开发算法作为初步练习。
感谢您查看此内容
答案 0 :(得分:2)
首先,有一种方法可以使Cramers规则完美:它将线性系统的代数解作为其系数中的有理函数。
然而,实际上,它有其局限性。虽然2x2系统是最完美的公式,并且仍然适用于3x3系统,但如果以直接的方式实施,其性能会随着每个额外维度而恶化。
使用Leverrier-Faddeev算法 a b 可以实现Cramers规则的几乎文字实现。它只需要计算矩阵乘积和矩阵迹线,以及矩阵对角线的操作。它不仅计算矩阵A的行列式(连同特征多项式的其他系数),它的迭代矩阵中还有adjugate或辅因子矩阵A # 。关于这个矩阵的一个有趣的事实是,它允许将A * x = b的解作为(A # * b)/ det(A),即A 的条目# * b已经是Cramers规则所要求的其他决定因素。
Leverrier-Faddeev需要n 4 + O(n 3 )操作。同样的结果可以通过更复杂的萨缪尔森 - Berkowitz算法获得,其具有该复杂性的三分之一,即n 4 / 3 + O(n 3 )。
如果系统(A | b)首先转换为三角形,则Cramers规则中所需的决定因素的计算变得非常简单。这可以通过Gauß消除,也就是LU分解(用于数值稳定性的旋转)或QR分解(最容易调试应该是Givens旋转的变体)来实现。然后,Cramers规则的有效应用是在三角系统中的后向替换。
答案 1 :(得分:1)
至少你的方法听起来不错;但是,我可能没有意识到任何更有效的方法。有趣的部分可能是弄清楚如何最好地实施行列式计算方法,显然它是not an inexpensive operation。
但是一旦你知道那是有效的,其余的听起来对我来说还算不错。缓存原始矩阵的行列式,在列中替换等。
答案 2 :(得分:0)
准确了解如何有效地做到这一点。
http://sandsduchon.org/duchon/math/determinantJava.html
提供无缝决定因素的方法,并提及矩阵分解。我还没有学到这一点,因为它不是HS级别的概念,但我使用它时遇到了一些问题,而且它是一种可靠的方法。
最终守则:
public static void main(String[] args) {
int[][] matrix = new int[3][3];
matrix[0] = new int[] { 3, 5, -1, -2 };
matrix[1] = new int[] { 1, -4, 2, 13 };
matrix[2] = new int[] { 2, 4, 3, 1 };
int[] r = crame(matrix);
info("x: " + r[0] + ", y: " + r[1] + ", z: " + r[2]);
for (int i = 0; i < matrix.length; i++) {
int[] base = matrix[i];
if (check(base, r, base[3])) {
info("System " + (i + 1) + " checks!");
} else {
info("System " + (i + 1) + " fails check!");
}
}
}
public static int getDet(int[][] a) {
int n = a.length - 1;
if (n < 0)
return 0;
int M[][][] = new int[n + 1][][];
M[n] = a; // init first, largest, M to a
// create working arrays
for (int i = 0; i < n; i++)
M[i] = new int[i + 1][i + 1];
return getDet(M, n);
} // end method getDecDet double [][] parameter
public static int getDet(int[][][] M, int m) {
if (m == 0)
return M[0][0][0];
int e = 1;
// init subarray to upper left mxm submatrix
for (int i = 0; i < m; i++)
for (int j = 0; j < m; j++)
M[m - 1][i][j] = M[m][i][j];
int sum = M[m][m][m] * getDet(M, m - 1);
// walk through rest of rows of M
for (int i = m - 1; i >= 0; i--) {
for (int j = 0; j < m; j++)
M[m - 1][i][j] = M[m][i + 1][j];
e = -e;
sum += e * M[m][i][m] * getDet(M, m - 1);
} // end for each row of matrix
return sum;
} // end getDecDet double [][][], int
public static int[] crame(int[][] m) {
int[] result;
if (m.length == 2) {
result = new int[m.length];
int D = getDet(m);
for (int i = 0; i < m.length; i++) {
result[i] = getDet(slide(m, i, m.length)) / D;
}
} else if (m.length == 3) {
result = new int[m.length];
int D = getDet(m);
for (int i = 0; i < m.length; i++) {
result[i] = (getDet(slide(m, i, m.length)) / D);
}
} else {
return new int[] {};
}
return result;
}
public static int[][] slide(int[][] base, int col, int fin) {
int[][] copy = new int[base.length][];
for (int i = 0; i < base.length; i++) {
int[] aMatrix = base[i];
int aLength = aMatrix.length;
copy[i] = new int[aLength];
System.arraycopy(aMatrix, 0, copy[i], 0, aLength);
}
for (int i = 0; i < base.length; i++) {
copy[i][col] = base[i][fin];
}
return copy;
}
public static int product(int[] a, int[] b) {
int p = 0;
int[] fin = new int[(a.length - 1)];
for (int x = 0; x < fin.length; x++) {
fin[x] = a[x] * b[x];
}
for (int f : fin) {
p += f;
}
return p;
}
public static boolean check(int[] a, int[] b, int z) {
return product(a, b) == z;
}
public static void info(String log) {
System.out.println(log);
}