第 31 天: 整数矩阵及其运算
感觉内容还是挺多的今天,矩阵就相当于是数组里面还有数组。由于代码太长,我就贴出相对核心的部分。
1.矩阵加法运算
矩阵之间也可以相加。把两个矩阵对应位置的单个元素相加,得到的新矩阵就是矩阵加法的结果。由其运算法则可知,只有行数和列数完全相同的矩阵才能进行加法运算。
矩阵之间相加没有顺序,假设A、B都是矩阵,则A+B=B+A。通常认为矩阵没有减法,若要与一个矩阵相减,在概念上是引入一个该矩阵的负矩阵,然后相加。A-B是A+(-B)的简写。图演示了两个三行三列矩阵的加法。
/**
*********************
* Add another matrix to me.
*
* @param paraMatrix The other matrix.
*********************
*/
public void add(IntMatrix paraMatrix) throws Exception {
// Step 1. Get the data of the given matrix.
int[][] tempData = paraMatrix.getData();
// Step 2. Size check.
if (data.length != tempData.length) {
throw new Exception(
"Cannot add matrices. Rows not match: " + data.length + " vs. " + tempData.length + ".");
} // Of if
if (data[0].length != tempData[0].length) {
throw new Exception(
"Cannot add matrices. Rows not match: " + data[0].length + " vs. " + tempData[0].length + ".");
} // Of if
// Step 3. Add to me.
for (int i = 0; i < data.length; i++) {
for (int j = 0; j < data[0].length; j++) {
data[i][j] += tempData[i][j];
} // Of for j
} // Of for i
}// Of add
/**
*********************
* Add two existing matrices.
*
* @param paraMatrix1 The first matrix.
* @param paraMatrix2 The second matrix.
* @return A new matrix.
*********************
*/
public static IntMatrix add(IntMatrix paraMatrix1, IntMatrix paraMatrix2) throws Exception {
// Step 1. Clone the first matrix.
IntMatrix resultMatrix = new IntMatrix(paraMatrix1);
// Step 2. Add the second one.
resultMatrix.add(paraMatrix2);
return resultMatrix;
}// Of add
这两段,前一个就是代表按照规则能不能加以及加这个动作,后一个则是完成两个存在的矩阵相加。
2.矩阵乘法运算
矩阵之间也可以进行乘法运算,但其运算过程相对复杂得多。与算术乘法不同,矩阵乘法并不是多个矩阵之和,它有自己的逻辑。其算法的具体描述为:假设m行n列的矩阵A和r行v列的矩阵B相乘得到矩阵C,则首先矩阵A和矩阵B必须满足n=r,也就是说,第一个矩阵的列数必须和第二个矩阵的行数相同。在运算时,第一个矩阵A的第i行的所有元素同第二个矩阵B第j列的元素对应相乘,并把相乘的结果相加,最终得到的值就是矩阵C的第i行第j列的值。
这个过程用数学公式描述为:
C(i,j)=A(i1,i2,i3……in)×B(j1,j2,j3……jv)
进而推出:
C(i,j)= i1×j1+i2 ×j2+i3×j3……+in×jv
从矩阵的乘法运算过程可以看出,矩阵A和矩阵B相乘的产生的矩阵C,必然是m行v列的。例如,一个5×3的矩阵同一个3×7的矩阵相乘,结果必然是产生一个5×7的矩阵。而一个5×3的矩阵同一个5×7的矩阵,则无法相乘。图演示了两组矩阵的乘法运算。
在图形变换时,经常用到多次变换,这会造成多个矩阵相乘。如果多个矩阵相乘,则等价于前两个矩阵相乘的结果再乘以第三个矩阵,以此向后类推。例如,假设ABCD都是矩阵,则A×B×C×D=((A×B)×C)×D。矩阵乘法同数字乘法不同,其运算的先后顺序十分敏感,矩阵A乘矩阵B的结果可能完全不同于矩阵B乘矩阵A的结果,有时甚至根本无法相乘。
/**
*********************
* Multiply two existing matrices.
*
* @param paraMatrix1 The first matrix.
* @param paraMatrix2 The second matrix.
* @return A new matrix.
*********************
*/
public static IntMatrix multiply(IntMatrix paraMatrix1, IntMatrix paraMatrix2) throws Exception {
// Step 1. Check size.
int[][] tempData1 = paraMatrix1.getData();
int[][] tempData2 = paraMatrix2.getData();
if (tempData1[0].length != tempData2.length) {
throw new Exception("Cannot multiply matrices: " + tempData1[0].length + " vs. " + tempData2.length + ".");
} // Of if
// Step 2. Allocate space.
int[][] resultData = new int[tempData1.length][tempData2[0].length];
// Step 3. Multiply.
for (int i = 0; i < tempData1.length; i++) {
for (int j = 0; j < tempData2[0].length; j++) {
for (int k = 0; k < tempData1[0].length; k++) {
resultData[i][j] += tempData1[i][k] * tempData2[k][j];
} // Of for k
} // Of for j
} // Of for i
// Step 4. Construct the matrix object.
IntMatrix resultMatrix = new IntMatrix(resultData);
return resultMatrix;
}// Of multiply
矩阵乘法相对难理解一些,特别是对于三重循环来说,但是要理解到乘法规则就相对好说,外层代表的第一个矩阵的行,中间那层就是第二个矩阵的列,最内层则是第二个矩阵每列里面的行。对于其他的一些细节方法,包括单位矩阵,Exception 的抛出与捕获机制,用 this 调用其它的构造方法以减少冗余代码,等等在老师的博客里都有提到,特别是Exception 的抛出与捕获机制,throws用法还要再进一步学习,相对来说理解没那么透彻,例如throws:“在开发中,如果去调用别人写的方法时,是否能知道别人写的方法是否会发生异常?这是很难判断的。针对这种情况,Java总允许在方法的后面使用throws关键字对外声明该方法有可能发生异常,这样调用者在调用方法时,就明确地知道该方法有异常,并且必须在程序中对异常进行处理,否则编译无法通过。”