Java实现行列式计算
Java实现行列式计算
前言
最近复习完了线性代数,好久没有碰编程的东西,为了稍微巩固一下,便在闲暇之余,简单写了一个小程序,用于计算行列的值。
基本结构说明
-
本文显示的计算方法的核心算法思想是迭代。面对多阶行列式,采用按列展开的方式进行计算,确定一个元素之后,将其对应的余子式提取出,视为新的行列式,以此类推,直到余子式的阶数小于三为止(2阶行列式直接按公式计算)。
-
采用键盘输入的方式,让使用者键入行列式的阶数以及各个元素。对于阶数和各个元素的键入与读取,分为了两个方法。目前阶数暂时限制在20以内,避免资源消耗过多。
-
一些行列式中可能存在分数,经计算之后会直接输出小数形式的结果,而有些情况,需要输出分数形式。于是便在结尾简单写了一个小数转分数的方法(最后补充的功能,经测试,功能尚不完善,待后续补充)
代码
package com.bk.pojo.pp.yuansu.info;
import java.lang.reflect.Method;
import java.util.Scanner;
/**
* 计算行列式
*/
public class CountHanglieshi {
// 设置一个全局的输入流
private final Scanner scanMain;
private final Scanner scanBreak;
// 设置二维数组存储行列式
private double[][] arr;
// 储存阶数,用于控制输入规范
private int size;
public CountHanglieshi() {
// 初始化输入流
// 主要输入流
scanMain = new Scanner(System.in);
// 是否提前停止请求输入流
scanBreak = new Scanner(System.in);
}
/**
* main函数
*
* @param args 入参
*/
public static void main(String[] args) {
CountHanglieshi countHanglieshi = new CountHanglieshi();
String method = "rlExpanding";
if (args != null && args.length > 0 && args[0] != null && "".equals(args[0])) {
method = args[0];
}
try {
countHanglieshi.service(method);
} catch (Exception e) {
// 出现错误进行统一处理
// 直接判断可能出现的错误为输入的参数有误
System.out.println("启动失败,请检查输入命令的参数是否有误");
}
}
/**
* 行列式按行按列展开
* <p>利用行列式展开原理进行计算
*/
public void rlExpanding() {
// 调用递归函数进行计算,要进行多次数的复制,存在较大的优化空间
double result = core(size, arr);
System.out.println("行列式的计算结果为: " + transferFs(result));
}
/**
* 核心代码
* <p>使用行列式展开方法计算行列式(使用递归)
*/
public double core(int rank, double[][] a) {
if (rank > 2) {
double result = 0;
for (int k = 0; k < rank; k++) {
// 取出余子式
double[][] newArr = new double[rank - 1][rank - 1];
int index = 0;
// 对数组进行赋值
for (int i = 0; i < rank; i++) {
if (k != i) {
for (int j = 1; j < rank; j++) {
// 如果该行不等于所在行
newArr[index][j - 1] = a[i][j];
}
// 到第下一行赋值
index++;
}
}
// 重点注意 由于此处取的是 a11 所以 (-1)^(1+1) = 1 可以进行处理
result += Math.pow(-1, (k + 1 + 1)) * a[k][0] * core(rank - 1, newArr);
}
// --------------------------------------
return result;
} else {
// 二级行列式计算
return a[0][0] * a[1][1] - a[0][1] * a[1][0];
}
}
/**
* 业务处理函数
*/
public void service(String method) {
//死循环实现连续计算
while (true) {
int row = readRow();
if (row != 0) {
// 初始化成功
// 数据的输入
if (readData(row)) {
// 数据录入成功,可以进行计算
// 通过反射,获取method方法进行计算 jdk1.8以上可以使用
try {
Class<CountHanglieshi> clazz = CountHanglieshi.class;
Method m = clazz.getMethod(method);
m.invoke(this);
System.out.print("是否继续计算(y/n):");
String s = scanBreak.nextLine();
if ("n".equals(s) || "N".equals(s)) {
System.exit(0);
}
} catch (Exception e) {
// 调用反射是出错
return;
}
}
} else {
System.out.println("行列式阶数不可为0,是否停止服务【y/n】)");
String s = scanBreak.nextLine();
if ("n".equals(s) || "N".equals(s)) {
System.exit(0);
}
}
}
}
/**
* 输入行列式的阶数(20以内)
*
* @return int 阶数
*/
public int readRow() {
System.out.println("-------------------------RowLineFormula----------------------------");
System.out.print("请输入要计算的行列式的阶数:");
int row = scanMain.nextInt();
size = row;
// 限制只能计算20阶以内的行列式
if (row > 1 && row <= 20) {
// 初始化 数据
arr = new double[row][row];
return row;
}
return 0;
}
/**
* 读取数据
*
* @return 判断用户是否选择退出程序, 并进行重新操作
*/
public boolean readData(int row) {
try {
System.out.println("输入行列式的数据(输入一行之后回车,每个数据之间使用空格进行分隔):");
scanMain.nextLine();
for (int i = 0; i < row; i++) {
System.out.print("第" + (i + 1) + "行: ");
String line = scanMain.nextLine();
String[] data = line.trim().split(" ");
if (data.length != row) {
System.out.println("数据输入格式错误,请重新输入(从第1行开始):");
i = -1;
} else {
for (int j = 0; j < row; j++) {
// 此处可能会报错,由于用户输入的错误信息
String datum = data[j];
String[] split = datum.split("/");
if (split.length > 1) {
arr[i][j] = Double.parseDouble(split[0]) / Double.parseDouble(split[1]);
} else {
arr[i][j] = Double.parseDouble(datum);
}
}
}
}
System.out.println("数据输入录入成功,正在计算行列式,请等待...");
} catch (NumberFormatException e) {
// 数据输入错误,进行处理
System.out.println("输入的数据有误,正在重新执行输入函数...");
return false;
}
return true;
}
/**
* 利用辗转相除法求得最大公约数
*
* @param xiaoshu 小数部分
* @param xiaoshuLength 小数部分长度
* @return 扣除公约数之后的结果
*/
public long gcd(long xiaoshu, long xiaoshuLength) {
return xiaoshuLength == 0 ? xiaoshu : gcd(xiaoshuLength, xiaoshu % xiaoshuLength);
}
/**
* 小数转分数
*/
public String transferFs(double num) {
String number = String.valueOf(num);
//定义长度为2的数组,分别存放整数位和小数位。
//利用.分割整数和小数
String[] array = number.split("\\.");
//整数部分
long zhengshu = Integer.parseInt(array[0]);
//小数部分
long xiaoshu = Integer.parseInt(array[1]);
//小数部分长度对应的位数
long xiaoshuLength = (int) Math.pow(10, array[1].length());
//公约数
long g = gcd(xiaoshu, xiaoshuLength);
//分母
long fenmu = xiaoshuLength / g;
//分母为1则不转化为分数
if (fenmu == 1) {
return String.valueOf(zhengshu + xiaoshu/g);
} else {
return (zhengshu*(fenmu) + (xiaoshu / g) + "/" + fenmu);
}
}
}

浙公网安备 33010602011771号