因课程作业需要, 经常要求解四元一次方程组, 甚至五元一次方程组, 为了避免重复的劳动遂有了写这个求解函数的想法.

  昨天在网上搜了一把, 没有很合适的, 且都是用克拉默法求解的. 所以冲动之下就写了自己的消元法求解函数.

  现把自己写的"消元算法", 以及在网上搜到的"克拉默求解算法" 献上,  很多地方有待改进,  欢迎拍砖.

 

  • 消元法.

  

1     /**
 2      * 用消元法求n元一次方程组的解 采用了递归的方法
 3      * 
 4      * @param q :
 5      *            方程组的系数矩阵 以二维数组的形式表示
 6      * @return 方程组的解 以数组形式返回
 7    */
 8     public double[] caculate(double[][] q) {
 9         int hang = q.length; // 行数
10         int shu = q[0].length; // 列数
11 
12         if (hang == 1) { // 化简到成为一元一次方程的时候
13             double[] x = { q[0][1] / q[0][0] };
14             return x;
15         } else {
16             double[][] temp = new double[hang - 1][shu - 1]; // 保存消元后的数组
17 
18         // 分开第一个系数为0 的行
19             List<double[]> zerorows = new ArrayList<double[]>(); // 第一个系数为0 的行
20             List<double[]> otherrows = new ArrayList<double[]>();
21 
22             for (int i = 0; i < hang; i++) {
23                 if (q[i][0] == 0)
24                     zerorows.add(q[i]);
25                 else
26                     otherrows.add(q[i]);
27             }
28 
29             for (int i = 0; i < otherrows.size() - 1; i++) {
30                 for (int j = 1; j < shu; j++) {
31                     temp[i][j-1] = otherrows.get(i+1)[0]*otherrows.get(i)[j]
32                           - otherrows.get(i)[0]*otherrows.get(i+1)[j];
33                 }
34             }
35             for (int i = 0; i < zerorows.size(); i++) {
36                 for (int j = 1; j < shu; j++) {
37                     temp[i + otherrows.size() - 1][j - 1] = zerorows.get(i)[j];
38                 }
39             }
40             double[] result = this.caculate(temp); // 递归,上步简化得到的结果
41 
42 
43       // 还要先判断 第一个数的系数是否为0
44             int row = 0;
45             while (q[row][0] == 0) {
46                 row++;
47             }
48 
49             double d = 0.00;
50             for (int i = 1; i < shu-1; i++)
51                 d += q[row][i] * result[i-1]; 
52             double x = (q[row][shu-1] - d) / q[row][0]; //将前面得到的结果 代入 求出当前 未知数
53 
54             double[] newresult = new double[result.length + 1];
55             newresult[0] = x;
56             for (int i = 0; i < result.length; i++) {
57                 newresult[i + 1] = result[i];
58             }
59 
60             return newresult;
61         }
62 
63     }


  • 克拉默法

克拉默法则解方程组过程在Java中 用克拉默法则解方程组2x1+x2-5x3+x4=8_克拉默法则解方程组过程在Java中

克拉默法则解方程组过程在Java中 用克拉默法则解方程组2x1+x2-5x3+x4=8_方程组_02

View Code

1 /**
  2 * @author zouyf 2008-4-7 本程序利用克拉默法则解多元一次方程组
  3 */
  4 public class GetMatrix
  5 {
  6     private double[][] savequot;// 保存变量系数
  7     private double[] constquot;// 保存常量系数
  8     private double[] saveResult;// 保存解的集合
  9 
 10     public GetMatrix(double quot[][])
 11     {
 12         int count = quot.length;
 13         savequot = new double[count][count];
 14         constquot = new double[count];
 15         saveResult = new double[count];
 16         int i = 0, j = 0;
 17         for (i = 0; i < count; i++)
 18         {
 19             for (j = 0; j < count; j++)
 20             {
 21                 savequot[i][j] = quot[i][j];
 22             }
 23             constquot[i] = quot[i][count];
 24             saveResult[i] = 0;
 25         }
 26     }
 27 
 28     private double getMatrixResult(double input[][])// 递归的方法求得某个行列式的值
 29     {
 30         if (input.length == 2)//递归出口,为二阶行列式时,直接返回
 31         {
 32             return input[0][0] * input[1][1] - input[0][1] * input[1][0];
 33         } 
 34         else
 35         {
 36             double[] temp = new double[input.length];//存放第一列的系数值
 37             double[][] tempinput = new double[input.length - 1][input.length - 1];
 38             double result = 0;
 39             for (int i = 0; i < input.length; i++)
 40             {
 41                 temp[i] = input[i][0];
 42                 int m = 0, n = 0;
 43                 for (int k = 0; k < input.length; k++)
 44                 {
 45                     if (k != i)
 46                     {
 47                         for (m = 0; m < input.length - 1; m++)
 48                         {
 49                             tempinput[n][m] = input[k][m + 1];//删除当前变量系数所在的行和列,得到减少一阶的新的行列式
 50                         }
 51                         n++;
 52                     }
 53                 }
 54                 if (i % 2 == 0)// 递归调用,利用代数余子式与相应系数变量的乘积之和得到多阶行列式的值
 55                 {
 56                     result = result + temp[i] * getMatrixResult(tempinput);
 57                 }
 58                 else
 59                 {
 60                     result = result - temp[i] * getMatrixResult(tempinput);
 61                 }
 62             }
 63             return result;
 64         }
 65     }
 66     
 67     private double[][] getReplaceMatrix(int i)// 用常数系数替换相应的变量系数,得到新的行列式
 68     {
 69         double tempresult[][] = new double[savequot.length][savequot.length];
 70         for (int m = 0; m < savequot.length; m++)
 71         {
 72             for (int n = 0; n < savequot.length; n++)
 73             {
 74                 if (i != m)
 75                 {
 76                     tempresult[n][m] = savequot[n][m];
 77                 } 
 78                 else
 79                 {
 80                     tempresult[n][i] = constquot[n];// 用常量系数替换当前变量系数
 81                 }
 82             }
 83         }
 84         return tempresult;
 85     }
 86 
 87     public double[] getResult()
 88     {
 89         double basic = 0;
 90         basic = getMatrixResult(savequot);//得到变量系数行列式的值
 91         if (Math.abs(basic) < 0.00001)
 92         {
 93             System.out.println("it dose not have the queue result!");
 94             return saveResult;
 95         }
 96         double[][] temp = new double[saveResult.length][saveResult.length];
 97         for (int i = 0; i < saveResult.length; i++)
 98         {
 99             temp = getReplaceMatrix(i);
100             saveResult[i] = getMatrixResult(temp) / basic;
101         }
102         return saveResult;
103     }
104 
105 
106 
107     public static void main(String[] args)
108     {
109         /**
110         * 测试方程组 
111         * 2a+b-5c+d=8 
112         * a-3b-6d=9 
113         * 2b-c+2d=-5 
114         * a+4b-7c+6d=0
115 */
116         double[][] test = { { 2, 1, -5, 1, 8 }, { 1, -3, 0, -6, 9 },
117                 { 0, 2, -1, 2, -5 }, { 1, 4, -7, 6, 0 } };
118         
119         GetMatrix gm = new GetMatrix(test);
120         double[] uu = new double[test.length];// 返回结果集
121         uu = gm.getResult();
122         for (int i = 0; i < uu.length; i++)
123         {
124             System.out.println(uu[i] + ",");
125         }
126     }
127 }

 

  • 比较

  两个算法比起来, 消元法看起来简洁一点. 

  但是还有一个问题, 第一个算法会出现小数精度的问题, 例如:

1     public static void main(String[] args) {
 2 
 3         double[][] xishu1 = { { 2.0, 4, 1, 8 }, { 4, -2, 2, 0 }, { 4, 1, 0, 6 } };
 4 
 5         Caculater c = new Caculater();
 6         double[] res = c.caculate(xishu1);
 7 
 8         for (double d : res)
 9             System.out.println(d);
10     }

  运行的结果是:

1 1.0999999999999996
2 1.6
3 -0.6

  很明显, 第一个解应该是1.1 才是正确的答案.

 

  小数精度的问题 留到日后解决吧.