【问题标题】:Multiplying two matrices in JavaJava中两个矩阵相乘
【发布时间】:2013-03-21 23:02:16
【问题描述】:

我目前正在开发一个表示矩阵的类,它表示任何通用的 mxn 矩阵。我已经计算出加法和标量乘法,但我正在努力开发两个矩阵的乘法。矩阵的数据保存在一个二维数组中。

方法看起来有点像这样:

   public Matrix multiply(Matrix A) {
            ////code
   }

它将返回产品矩阵。这是右边的乘法。所以,如果我调用 A.multiply(B) 那么它将返回矩阵 AB,B 在右边。

我还不需要担心检查是否在给定矩阵上定义了乘法,我可以假设我会得到正确维度的矩阵。

有没有人知道一个简单的算法,甚至可能用伪代码来执行乘法过程?

提前致谢。

【问题讨论】:

  • 你尝试过什么吗?或者你问过谷歌叔叔吗?
  • 我尝试了谷歌,但使用我熟悉的东西找不到任何东西。我不关心效率,只是真正容易编程的东西。我自己尝试在 for 循环中使用 for 循环,但没有成功。我真的有点难以弄清楚。我认为这是累了,我最终会到达那里:p 但是网上的一些提示总是有帮助的。

标签: java arrays matrix multidimensional-array multiplication


【解决方案1】:

矩阵 A (l x m) 和 B (m x n) 的乘积在数学上定义为由元素组成的矩阵 C (l x n):

        m
c_i_j = ∑  a_i_k * b_k_j
       k=1

因此,如果您对速度不太感兴趣,您可能会对直接的 O(n^3) 实现感到满意:

  for (int i=0; i<l; ++i)
    for (int j=0; j<n; ++j)
      for (int k=0; k<m; ++k)
        c[i][j] += a[i][k] * b[k][j]  

如果您想加快速度,您可能需要检查其他替代方案,例如 Strassen 算法(请参阅:Strassen 算法)。

但请注意 - 特别是当您在现代处理器架构上乘以小矩阵时,速度在很大程度上取决于矩阵数据和乘法顺序的排列方式,以充分利用缓存行。

我非常怀疑是否有机会通过使用虚拟机来影响这个因素,所以我不确定是否要考虑这一点。

【讨论】:

  • 啊,非常感谢 :) 这行得通。效率并不重要,所以 O(n^3) 复杂度就可以了。我所需要的只是让算法正确地执行该过程,不管需要多长时间,这都很好。再次感谢:)
【解决方案2】:

Java。矩阵乘法。

这里是“执行乘法过程的代码”。使用不同大小的矩阵进行测试。

public class Matrix {

/**
 * Matrix multiplication method.
 * @param m1 Multiplicand
 * @param m2 Multiplier
 * @return Product
 */
    public static double[][] multiplyByMatrix(double[][] m1, double[][] m2) {
        int m1ColLength = m1[0].length; // m1 columns length
        int m2RowLength = m2.length;    // m2 rows length
        if(m1ColLength != m2RowLength) return null; // matrix multiplication is not possible
        int mRRowLength = m1.length;    // m result rows length
        int mRColLength = m2[0].length; // m result columns length
        double[][] mResult = new double[mRRowLength][mRColLength];
        for(int i = 0; i < mRRowLength; i++) {         // rows from m1
            for(int j = 0; j < mRColLength; j++) {     // columns from m2
                for(int k = 0; k < m1ColLength; k++) { // columns from m1
                    mResult[i][j] += m1[i][k] * m2[k][j];
                }
            }
        }
        return mResult;
    }

    public static String toString(double[][] m) {
        String result = "";
        for(int i = 0; i < m.length; i++) {
            for(int j = 0; j < m[i].length; j++) {
                result += String.format("%11.2f", m[i][j]);
            }
            result += "\n";
        }
        return result;
    }

    public static void main(String[] args) {
        // #1
        double[][] multiplicand = new double[][] {
                {3, -1, 2},
                {2,  0, 1},
                {1,  2, 1}
        };
        double[][] multiplier = new double[][] {
                {2, -1, 1},
                {0, -2, 3},
                {3,  0, 1}
        };
        System.out.println("#1\n" + toString(multiplyByMatrix(multiplicand, multiplier)));
        // #2
        multiplicand = new double[][] {
                {1, 2, 0},
                {-1, 3, 1},
                {2, -2, 1}
        };
        multiplier = new double[][] {
                {2},
                {-1},
                {1}
        };
        System.out.println("#2\n" + toString(multiplyByMatrix(multiplicand, multiplier)));
        // #3
        multiplicand = new double[][] {
                {1, 2, -1},
                {0,  1, 0}
        };
        multiplier = new double[][] {
                {1, 1, 0, 0},
                {0, 2, 1, 1},
                {1, 1, 2, 2}
        };
        System.out.println("#3\n" + toString(multiplyByMatrix(multiplicand, multiplier)));
    }
}

输出:

#1
      12.00      -1.00       2.00
       7.00      -2.00       3.00
       5.00      -5.00       8.00

#2
       0.00
      -4.00
       7.00

#3
       0.00       4.00       0.00       0.00
       0.00       2.00       1.00       1.00

【讨论】:

    【解决方案3】:

    在这个答案中,我创建了一个名为 Matrix 的类,另一个名为 MatrixOperations 的类定义了可以对矩阵执行的各种操作(当然,行操作除外)。但我将从 MatrixOperations 中提取乘法代码。完整的项目可以在我的GitHub页面here找到。

    下面是Matrix类的定义。

    package app.matrix;
    
    import app.matrix.util.MatrixException;
    
    public class Matrix {
    
    private double[][] entries;
    
    public void setEntries(double[][] entries) {
        this.entries = entries;
    }
    
    private String name;
    
    public double[][] getEntries() {
        return entries;
    }
    
    public String getName() {
        return name;
    }
    
    public void setName(String name) {
        this.name = name;
    }
    
    public class Dimension {
        private int rows;
        private int columns;
    
        public int getRows() {
            return rows;
        }
    
        public void setRows(int rows) {
            this.rows = rows;
        }
    
        public int getColumns() {
            return columns;
        }
    
        public void setColumns(int columns) {
            this.columns = columns;
        }
    
        public Dimension(int rows, int columns) {
            this.setRows(rows);
            this.setColumns(columns);
        }
    
        @Override
        public boolean equals(Object obj) {
            if(obj instanceof Dimension){
                return (this.getColumns() == ((Dimension) obj).getColumns()) && (this.getRows() == ((Dimension) obj).getRows());
            }
            return false;
        }
    }
    
    private Dimension dimension;
    
    public Dimension getDimension() {
        return dimension;
    }
    
    public void setDimension(Dimension dimension) {
        this.dimension = dimension;
    }
    
    public Matrix(int dimension, String name) throws MatrixException {
        if (dimension == 0) throw new MatrixException(ZERO_UNIT_DIMENSION);
        else this.setEntries(new double[Math.abs(dimension)][Math.abs(dimension)]);
        this.setDimension(new Dimension(dimension, dimension));
        this.setName(name);
    }
    
    public Matrix(int dimensionH, int dimensionV, String name) throws MatrixException {
        if (dimensionH == 0 || dimensionV == 0) throw new MatrixException(ZERO_UNIT_DIMENSION);
        else this.setEntries(new double[Math.abs(dimensionH)][Math.abs(dimensionV)]);
        this.setDimension(new Dimension(dimensionH, dimensionV));
        this.setName(name);
    
    }
    
    private static final String OVERFLOW_ITEMS_MSG = "The values are too many for the matrix's specified dimensions";
    private static final String ZERO_UNIT_DIMENSION = "Zero cannot be a value for a dimension";
    
    public Matrix(int dimensionH, int dimensionV, String name, double... values) throws MatrixException {
        if (dimensionH == 0 || dimensionV == 0) throw new MatrixException(ZERO_UNIT_DIMENSION);
        else if (values.length > dimensionH * dimensionV) throw new MatrixException(Matrix.OVERFLOW_ITEMS_MSG);
        else this.setEntries(new double[Math.abs(dimensionH)][Math.abs(dimensionV)]);
        this.setDimension(new Dimension(dimensionH, dimensionV));
        this.setName(name);
    
        int iterator = 0;
        int j;
        for (int i = 0; i < dimensionH; i++) {
            j = 0;
            while (j < dimensionV) {
                this.entries[i][j] = values[iterator];
                j++;
                iterator++;
            }
        }
    }
    
    public Matrix(Dimension dimension) throws MatrixException {
        this(dimension.getRows(), dimension.getColumns(), null);
    }
    
    public static Matrix identityMatrix(int dim) throws MatrixException {
        if (dim == 0) throw new MatrixException(ZERO_UNIT_DIMENSION);
    
        double[] i = new double[dim * dim];
        int constant = dim + 1;
        for (int j = 0; j < i.length; j = j + constant) {
            i[j] = 1.0;
        }
    
        return new Matrix(dim, dim, null, i);
    }
    
    public String toString() {
    
        StringBuilder builder = new StringBuilder("Matrix \"" + (this.getName() == null ? "Null Matrix" : this.getName()) + "\": {\n");
    
        for (int i = 0; i < this.getDimension().getRows(); i++) {
            for (int j = 0; j < this.getDimension().getColumns(); j++) {
                if (j == 0) builder.append("\t");
                builder.append(this.entries[i][j]);
                if (j != this.getDimension().getColumns() - 1)
                    builder.append(", ");
            }
            if (i != this.getDimension().getRows()) builder.append("\n");
        }
    
        builder.append("}");
    
        return builder.toString();
    }
    
    public boolean isSquare() {
        return this.getDimension().getColumns() == this.getDimension().getRows();
    }
    

    }

    这是MatrixOperations中矩阵乘法的代码方法

    public static Matrix multiply(Matrix matrix1, Matrix matrix2) throws MatrixException {
    
        if (matrix1.getDimension().getColumns() != matrix2.getDimension().getRows())
            throw new MatrixException(MATRIX_MULTIPLICATION_ERROR_MSG);
    
        Matrix retVal = new Matrix(matrix1.getDimension().getRows(), matrix2.getDimension().getColumns(), matrix1.getName() + " x " + matrix2.getName());
    
    
        for (int i = 0; i < matrix1.getDimension().getRows(); i++) {
            for (int j = 0; j < matrix2.getDimension().getColumns(); j++) {
                retVal.getEntries()[i][j] = sum(arrayProduct(matrix1.getEntries()[i], getColumnMatrix(matrix2, j)));
            }
        }
    
        return retVal;
    }
    

    下面是 sum、arrayProduct 和 getColumnMatrix 方法的代码

    private static double sum(double... values) {
        double sum = 0;
        for (double value : values) {
            sum += value;
        }
        return sum;
    }
    
    private static double[] arrayProduct(double[] arr1, double[] arr2) throws MatrixException {
        if (arr1.length != arr2.length) throw new MatrixException("Array lengths must be the same");
        double[] retVal = new double[arr1.length];
        for (int i = 0; i < arr1.length; i++) {
            retVal[i] = arr1[i] * arr2[i];
        }
    
        return retVal;
    }
    
    
    private static double[] getColumnMatrix(Matrix matrix, int col) {
        double[] ret = new double[matrix.getDimension().getRows()];
        for (int i = 0; i < matrix.getDimension().getRows(); i++) {
            ret[i] = matrix.getEntries()[i][col];
        }
        return ret;
    }
    

    【讨论】:

      【解决方案4】:

      对多个任意维数组尝试此代码并打印它。觉得这个比较简单,任何人都可以理解。

      public class Test
      {
      
        public static void main(String[] args)
        {
          int[][] array1 = {
              { 1, 4, -2 },
              { 3, 5, -6 },
              { 4, 5, 2 }
          };
      
          int[][] array2 = {
              { 5, 2, 8, -1 },
              { 3, 6, 4, 5 },
              { -2, 9, 7, -3 }
          };
          Test test = new Test();
          test.printArray(test.multiplication(array1, array2));
        }
      
        private int[][] multiplication(int[][] array1, int[][] array2)
        {
          int r1, r2, c1, c2;
          r1 = array1.length;
          c1 = array1[0].length;
      
          r2 = array2.length;
          c2 = array2[0].length;
      
          int[][] result;
          if (c1 != r2)
          {
            System.out.println("Error!");
            result = new int[0][0];
          }
          else
          {
            result = new int[r1][c2];
      
            for (int i = 0; i < r1; i++)//2
            {
              for (int j = 0; j < c2; j++)//4
              {
                for (int k = 0; k < c1; k++)
                {
                  result[i][j] += array1[i][k] * array2[k][j];
                }
              }
            }
          }
      
          return result;
        }
      
        private void printArray(int[][] array)
        {
          for (int[] arr : array)
          {
            for (int element : arr)
            {
              System.out.print(element + " ");
            }
            System.out.println();
          }
        }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-01-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-04-01
        相关资源
        最近更新 更多