programming-examples/java/Data_Structures/Determinant.java

185 lines
4.6 KiB
Java
Raw Normal View History

2019-11-15 12:59:38 +01:00
import java.math.BigDecimal;
import java.math.BigInteger;
public class Determinant {
public static double det(double[][] a) {
final double eps = 1e-10;
int n = a.length;
double res = 1;
boolean[] used = new boolean[n];
for (int i = 0; i < n; i++) {
int p;
for (p = 0; p < n; p++)
if (!used[p] && Math.abs(a[p][i]) > eps)
break;
if (p == n)
return 0;
res *= a[p][i];
used[p] = true;
double z = 1 / a[p][i];
for (int j = 0; j < n; j++)
a[p][j] *= z;
for (int j = 0; j < n; ++j)
if (j != p) {
z = a[j][i];
for (int k = 0; k < n; ++k)
a[j][k] -= z * a[p][k];
}
}
return res;
}
public static BigInteger detCrout(BigDecimal a[][], int n) {
try {
for (int i = 0; i < n; i++) {
boolean nonzero = false;
for (int j = 0; j < n; j++)
if (a[i][j].compareTo(new BigDecimal(BigInteger.ZERO)) > 0)
nonzero = true;
if (!nonzero)
return BigInteger.ZERO;
}
BigDecimal scaling[] = new BigDecimal[n];
for (int i = 0; i < n; i++) {
BigDecimal big = new BigDecimal(BigInteger.ZERO);
for (int j = 0; j < n; j++)
if (a[i][j].abs().compareTo(big) > 0)
big = a[i][j].abs();
scaling[i] = (new BigDecimal(BigInteger.ONE)).divide(big, 100, BigDecimal.ROUND_HALF_EVEN);
}
int sign = 1;
for (int j = 0; j < n; j++) {
for (int i = 0; i < j; i++) {
BigDecimal sum = a[i][j];
for (int k = 0; k < i; k++)
sum = sum.subtract(a[i][k].multiply(a[k][j]));
a[i][j] = sum;
}
BigDecimal big = new BigDecimal(BigInteger.ZERO);
int imax = -1;
for (int i = j; i < n; i++) {
BigDecimal sum = a[i][j];
for (int k = 0; k < j; k++)
sum = sum.subtract(a[i][k].multiply(a[k][j]));
a[i][j] = sum;
BigDecimal cur = sum.abs();
cur = cur.multiply(scaling[i]);
if (cur.compareTo(big) >= 0) {
big = cur;
imax = i;
}
}
if (j != imax) {
for (int k = 0; k < n; k++) {
BigDecimal t = a[j][k];
a[j][k] = a[imax][k];
a[imax][k] = t;
}
BigDecimal t = scaling[imax];
scaling[imax] = scaling[j];
scaling[j] = t;
sign = -sign;
}
if (j != n - 1)
for (int i = j + 1; i < n; i++)
a[i][j] = a[i][j].divide(a[j][j], 100, BigDecimal.ROUND_HALF_EVEN);
}
BigDecimal result = new BigDecimal(1);
if (sign == -1)
result = result.negate();
for (int i = 0; i < n; i++)
result = result.multiply(a[i][i]);
return result.divide(BigDecimal.valueOf(1), 0, BigDecimal.ROUND_HALF_EVEN).toBigInteger();
} catch (Exception e) {
return BigInteger.ZERO;
}
}
public static BigInteger detBigInteger(long[][] a) {
int n = a.length;
BigInteger[][] b = new BigInteger[n][n];
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)
b[i][j] = BigInteger.valueOf(a[i][j]);
int sign = 1;
int[] pow = new int[n];
for (int i = 0; i < n; ++i) {
int k = i;
for (int j = i + 1; j < n; ++j) {
if (b[k][i].equals(BigInteger.ZERO) || !b[j][i].equals(BigInteger.ZERO)
&& b[k][i].abs().compareTo(b[j][i].abs()) > 0) {
k = j;
}
}
if (b[k][i].equals(BigInteger.ZERO))
return BigInteger.ZERO;
if (i != k) {
sign = -sign;
BigInteger[] t = b[i];
b[i] = b[k];
b[k] = t;
}
++pow[i];
for (int j = i + 1; j < n; ++j)
if (!b[j][i].equals(BigInteger.ZERO)) {
for (int p = i + 1; p < n; ++p) {
b[j][p] = b[j][p].multiply(b[i][i]).subtract(b[i][p].multiply(b[j][i]));
}
--pow[i];
}
}
BigInteger det = BigInteger.ONE;
for (int i = 0; i < n; i++)
if (pow[i] > 0)
det = det.multiply(b[i][i].pow(pow[i]));
for (int i = 0; i < n; i++)
if (pow[i] < 0)
det = det.divide(b[i][i].pow(-pow[i]));
if (sign < 0)
det = det.negate();
return det;
}
// Usage example
public static void main(String[] args) {
check(new long[][] { { 2, 4, 3, 5, 4 }, { 5, 4, 0, 2, 4 }, { 0, 5, 5, 2, 3 }, { 1, 0, 4, 3, 0 },
{ 0, 5, 1, 4, 4 } });
check(new long[][] { { 3, 2, 2 }, { 0, 0, 5 }, { 4, 3, 1 } });
check(new long[][] { { 2, 2, 2 }, { 1, 2, 0 }, { 2, 2, 0 } });
check(new long[][] { { 1, 2 }, { 3, 4 } });
check(new long[][] { { 2, 4 }, { 0, 3 } });
}
private static void check(long[][] a1) {
int n = a1.length;
double[][] a2 = new double[n][n];
BigDecimal[][] a3 = new BigDecimal[n][n];
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
a2[i][j] = a1[i][j];
a3[i][j] = BigDecimal.valueOf(a1[i][j]);
}
}
double res1 = det(a2);
BigInteger res2 = detCrout(a3, n);
BigInteger res3 = detBigInteger(a1);
System.out.println(res1 + " " + res2 + " " + res3);
}
}