【问题标题】:Multiply 2 matrices in Javascript在Javascript中乘以2个矩阵
【发布时间】:2015-01-28 01:53:20
【问题描述】:

我正在做一个乘以 2 个矩阵的函数。矩阵将始终具有相同数量的行和列。 (2x2、5x5、23x23、...)

当我打印它时,它不起作用。为什么?

例如,如果我创建两个 2x2 矩阵:

矩阵A:

[1][2]

[3][4]

矩阵B:

[5][6]

[7][8]

结果应该是:

[19][22]

[43][50]

(http://ncalculators.com/matrix/2x2-matrix-multiplication-calculator.htm)

但是,我明白了:

[19][undefined]

[22][indefined]

function multiplyMatrix(matrixA, matrixB)
{
    var result = new Array();//declare an array   

    //var numColsRows=$("#matrixRC").val();
    numColsRows=2;
    
    //iterating through first matrix rows
    for (var i = 0; i < numColsRows; i++) 
    {
        //iterating through second matrix columns
        for (var j = 0; j < numColsRows; j++) 
        { 
            var matrixRow = new Array();//declare an array
            var rrr = new Array();
            var resu = new Array();
            //calculating sum of pairwise products
            for (var k = 0; k < numColsRows; k++) 
            {
                rrr.push(parseInt(matrixA[i][k])*parseInt(matrixB[k][j]));
            }//for 3
            resu.push(parseInt(rrr[i])+parseInt(rrr[i+1]));

            result.push(resu);
            //result.push(matrixRow);
        }//for 2
    }//for 1
    return result;
}// function multiplyMatrix

【问题讨论】:

  • 您是否尝试在浏览器内置调试器或 Firebug 中调试代码?
  • 使用您的代码,我得到的输出与您声称的不同 - multiplyMatrix([[1,2],[3,4]], [[5,6],[7,8]]) 返回 [[19],[22],[NaN],[Nan]]

标签: javascript arrays matrix matrix-multiplication


【解决方案1】:

这是我的带有数学错误处理的 ES6 解决方案:

const matrixDot = (A, B) => {
  // Error handling
  const mx = [A, B];
  const cols = mx.map((matrix) => matrix[0].length);
  if (!mx.every((matrix, i) => matrix.every((row) => row.length === cols[i]))) {
    throw new Error(
      'All rows in a matrix must have the same number of columns'
    );
  } else if (cols[0] !== B.length) {
    throw new Error(
      'The number of columns in the 1st matrix must be equal to the number of rows in the 2nd matrix'
    );
  }

  // Calculations
  return A.map((rowA) =>
    B[0].map((_, xb) =>
      rowA.reduce((acc, itemA, yb) => acc + itemA * B[yb][xb], 0)
    )
  );
};

// Example
const A = [
  [3, 2, 5],
  [6, 4, 1],
];
const B = [
  [2, 6],
  [5, 3],
  [1, 4],
];
console.log(matrixDot(A, B));

希望对某人有所帮助;)

【讨论】:

    【解决方案2】:

    const getDot = (arrA, arrB, row, col) => {
        return arrA[row].map((val, i) => (val * arrB[i][col]))
      .reduce((valA, valB) => valA + valB);
    }
    
    const multiplyMatricies = (a, b) => {
        let matrixShape = new Array(a.length).fill(0)
          .map(() => new Array(b[0].length).fill(0));
            return matrixShape.map((row, i) =>
              row.map((val, j) => getDot(a, b, i, j)));
          }
    
        const arrA = [
          [1, 3, 0],
          [2, 1, 1]
        ];
        const arrB = [
          [1, 2, 0, 1],
          [2, 3, 1, 2],
          [1, 2, 1, 1]
        ];
    
        let product = multiplyMatricies(arrA, arrB);
        console.log("product:", product);

    【讨论】:

      【解决方案3】:

      此版本将行存储为临时对象,从而减少了有效的索引查找量。通过这个benchmark,与不存储行的版本相比,实现的性能几乎快了 2 倍。

      function multiply(a, b) {
          let aRows = a.length;
          let aCols = a[0].length;
          let bCols = b[0].length;
          let result = new Array(aRows); 
          for (let r = 0; r < aRows; ++r) {
              const row = new Array(bCols);
              result[r] = row;
              const ar = a[r];
              for (let c = 0; c < bCols; ++c) {
                  let sum = 0.;     
                  for (let i = 0; i < aCols; ++i) {
                      sum += ar[i] * b[i][c];
                  }
                  row[c] = sum;  
              }
          }
          return result;
      }
      
      const m = multiply(
              [[8, 3], [2, 4], [3, 6]],
              [[1, 2, 3], [4, 6, 8]]
          );
      console.log(m);
      function display(m) {
          for (var r = 0; r < m.length; ++r) {
              document.write('&nbsp;&nbsp;'+m[r].join(' ')+'<br />');
          }
      }
      
      var a = [[8, 3], [2, 4], [3, 6]],
          b = [[1, 2, 3], [4, 6, 8]];
      document.write('matrix a:<br />');
      display(a);
      document.write('matrix b:<br />');
      display(b);
      document.write('a * b =<br />');
      display(multiply(a, b));

      【讨论】:

        【解决方案4】:

        对于那些对纯函数解决方案感兴趣的人:

        let MatrixProd = (A, B) =>
          A.map((row, i) =>
            B[0].map((_, j) =>
              row.reduce((acc, _, n) =>
                acc + A[i][n] * B[n][j], 0
              )
            )
          )
        

        您的浏览器的测试代码:

        let A = [[8, 3], [2, 4], [3, 6]];
        let B = [[1, 2, 3], [4, 6, 8]];
        console.table(MatrixProd(A,B));
        

        【讨论】:

          【解决方案5】:

          我知道这是一个老问题,但我建议切换到我的答案。

          我的解决方案性能很好,因为它使用了Map Reduce 功能

          //The chosen one
          function matrixDot (A, B) {
              var result = new Array(A.length).fill(0).map(row => new Array(B[0].length).fill(0));
          
              return result.map((row, i) => {
                  return row.map((val, j) => {
                      return A[i].reduce((sum, elm, k) => sum + (elm*B[k][j]) ,0)
                  })
              })
          }
          
          var print = m => m.forEach(r => document.write(`&nbsp;&nbsp;${r.join(' ')}<br/>`)) 
          
          var a = [[8, 3], [2, 4], [3, 6]]
          var b = [[1, 2, 3], [4, 6, 8]]
          
          document.write('matrix a:<br />');
          print(a);
          document.write('matrix b:<br />');
          print(b);
          document.write('a * b =<br />');
          print(matrixDot(a,b));

          【讨论】:

            【解决方案6】:

            您可以通过 动态编程 使用 Memoization 来解决这个问题。这是一个描述优化技术的术语,您可以缓存以前计算的结果,并在再次需要相同的计算时返回缓存的结果。

                    let mat1 = [[1, 2, 3], [2, 1, 2]];
            
                    let mat2 = [[1, 2], [1, 2], [1, 2]];
            
                    function matrixMulti(x, y) {
                      let saveComputation = {};
                      let finalMat = [],
                           length=x.length,
                           length1 =  y[0].length,
                           length2 =  y.length;
                      for (let i = 0; i < length; i++) {
                        finalMat.push([]);
                        for (let j = 0; j < length1; j++) {
                          finalMat[i][j] = 0;
                          for (let k = 0; k < length2; k++) {
                // check if we already computed this calculation or not
                            if (saveComputation[y[k][j] + '*' + x[i][k]] || saveComputation[x[i][k] + '*' + y[k][j]]) {
                              finalMat[i][j] = finalMat[i][j] + saveComputation[y[k][j] + '*' + x[i][k]];
                            } else {
            // save if not computed
                              saveComputation[x[i][k] + '*' + y[k][j]] = x[i][k] * y[k][j]; // check format below how it is saved.
                              saveComputation[y[k][j] + '*' + x[i][k]] = x[i][k] * y[k][j];
                              finalMat[i][j] = finalMat[i][j] + saveComputation[y[k][j] + '*' + x[i][k]];
                            }
                          }
                        }
                      }
            
                      console.log(finalMat);
                    }
            
                    matrixMulti(mat1, mat2);
            

            对于上述saveComputation的输入值将是

            { '1*1': 1,
              '2*1': 2,
              '1*2': 2,
              '3*1': 3,
              '1*3': 3,
              '2*2': 4,
              '3*2': 6,
              '2*3': 6 }
            

            【讨论】:

            • 您是否有任何测试用例可以衡量这种态度的好处?它增加了代码意外的复杂性,乘法是一个单一的机器指令,它比解析数组键和查找成本更低。我的猜测是,与经典解决方案相比,您的解决方案实际上
            【解决方案7】:

            npm install express

            节点服务器.js

            var express = require('express');
            var app = express();
            
            
            var A=new Array(3);
            var B=new Array(3);
            var preA = [ 1, 2, 3, 4, 5, 6,7, 8, 9 ];
            var preB = [ 1,1 ,1,2,2, 2,3, 3, 3 ];
            
            //#########################preparing blank 3*3 matrix A and B###############
            for(i=0;i<3;i++){
                A[i]=new Array(3);
                B[i]=new Array(3);
            }
            
            
            
            //#####################Assigning values to matrix places from predefine arrays preA and preB #####
            var k=0;
            for(i=0;i<3;i++){
                for(j=0;j<3;j++){
            
                    A[i][j]=preA[k];
                    B[i][j]=preB[k];
                    k++;
                }
            };
            
            
            console.log('################################');
            console.log('First matrix:');
            console.log(A[0]);
            console.log(A[1]);
            console.log(A[2]);
            console.log('');
            console.log('################################');
            console.log('Second matrix:');
            console.log(B[0]);
            console.log(B[1]);
            console.log(B[2]);
            
            //###################### multiplication logic as disscussed ################
            var result =[];
             for (var i = 0; i < 3; i++) {
                    result[i] = new Array(3);
                    for (var j = 0; j < 3; j++) {
                        var sum = 0;
                        for (var k = 0; k < 3; k++) {
                            sum += A[i][k] * B[k][j];
                        }
                        result[i][j] = sum;
                    }
                }
            console.log('');
            console.log('################################');
            console.log('################################');
            console.log('After Multiplication');
            
            console.log(result[0]);
            console.log(result[1]);
            console.log(result[2]);
            
            
            
            app.listen(9999);
            

            【讨论】:

            • 大声笑,我喜欢你的解决方案是创建一个 node.js 服务器。您的操作是假设人们也安装了 npm,但对于某些人(比如我)来说并非如此。 idk 如果您的算法实际上与节点分开工作。我只是觉得你决定让节点作为测试算法的先决条件很有趣。
            【解决方案8】:

            如果您想走疯狂的路线,您还可以使用 WebGL 工具中的顶点转换来做一些事情,这些工具现在在某些现代浏览器中可用。

            不确定这是否会以与 OpenCL 中的向量转换相同的方式工作(**实际上它们是类型等效/可互操作的),但总体思路是:

            • 将值添加到缓冲区

            • “假装”它是一个顶点数组

            • 使用 GPU 引擎转换 en-mass

            • 从向量中检索修改后的值

            (在此处查看演示) http://www.html5rocks.com/en/tutorials/webgl/webgl_transforms/

            只是通常循环方法的替代方法。老实说,考虑到 OpenCL 就是为这种事情而设计的,这有点麻烦

            在 OpenCL 1.2 规范中,可以使用 OpenCL 加载和转换来自 OpenGL 的顶点缓冲区(请参阅。https://software.intel.com/en-us/articles/opencl-and-opengl-interoperability-tutorial

            【讨论】:

            • 这太棒了!!不知道为什么这被否决了。最终我认为所有线性代数运算都应该在浏览器中以这种方式完成。
            【解决方案9】:

            您可以使用来自:http://tech.pro/tutorial/1527/matrix-multiplication-in-functional-javascript 的 multiplyMatrices() 函数,它就像魅力一样。示例(您可以在 Chrome 和 Firefox 控制台中使用 console.table() 打印带有样式的矩阵):

            function multiplyMatrices(m1, m2) {
                var result = [];
                for (var i = 0; i < m1.length; i++) {
                    result[i] = [];
                    for (var j = 0; j < m2[0].length; j++) {
                        var sum = 0;
                        for (var k = 0; k < m1[0].length; k++) {
                            sum += m1[i][k] * m2[k][j];
                        }
                        result[i][j] = sum;
                    }
                }
                return result;
            }
            
            var m1 = [[1,2],[3,4]]
            var m2 = [[5,6],[7,8]]
            
            var mResult = multiplyMatrices(m1, m2)
            
            /*In Google Chrome and Firefox you can do:*/
            
            console.table(mResult) /* it shows the matrix in a table */

            【讨论】:

              【解决方案10】:

              您对各种临时数组感到困惑。 undefined 值是由最内层循环下方的行上的越界访问引起的。

              我建议您坚持为乘法结果创建一个数组。您可能知道,问题在于 JavaScript 不允许您初始化多维数组。要创建一个二维数组,您必须初始化一个一维数组,然后遍历其元素并将每个元素初始化为一维数组。

              function multiply(a, b) {
                var aNumRows = a.length, aNumCols = a[0].length,
                    bNumRows = b.length, bNumCols = b[0].length,
                    m = new Array(aNumRows);  // initialize array of rows
                for (var r = 0; r < aNumRows; ++r) {
                  m[r] = new Array(bNumCols); // initialize the current row
                  for (var c = 0; c < bNumCols; ++c) {
                    m[r][c] = 0;             // initialize the current cell
                    for (var i = 0; i < aNumCols; ++i) {
                      m[r][c] += a[r][i] * b[i][c];
                    }
                  }
                }
                return m;
              }
              
              function display(m) {
                for (var r = 0; r < m.length; ++r) {
                  document.write('&nbsp;&nbsp;'+m[r].join(' ')+'<br />');
                }
              }
              
              var a = [[8, 3], [2, 4], [3, 6]],
                  b = [[1, 2, 3], [4, 6, 8]];
              document.write('matrix a:<br />');
              display(a);
              document.write('matrix b:<br />');
              display(b);
              document.write('a * b =<br />');
              display(multiply(a, b));

              【讨论】:

              • 我在 MSE 上将它用于中等矩阵。它工作正常。
              猜你喜欢
              • 2017-11-19
              • 1970-01-01
              • 2011-08-30
              • 2021-12-12
              • 1970-01-01
              • 1970-01-01
              • 2013-06-18
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多