【问题标题】:Matrix Multiplication in javascriptjavascript中的矩阵乘法
【发布时间】:2018-12-03 14:55:09
【问题描述】:

我的项目遇到了一个与矩阵乘法有关的问题。我必须将两个矩阵相乘,一个是我制作的,一个是参数。但是,它必须通过 jasmine 测试,目前由于 NaN 错误而未通过。任何帮助将不胜感激。谢谢。 我的矩阵代码:

class Matrix {
  constructor(pX0, pX1, pX2, pY0, pY1, pY2, pZ0, pZ1, pZ2) {
    this.Matrix = [
      [pX0, pX1, pX2],
      [pY0, pY1, pY2],
      [pZ0, pZ1, pZ2]
    ];
  }
  getX0() {
    return this.mX0;
  }
  setX0(pX0) {
    this.mX0 = pX0;
  }
  getX1() {
    return this.mX1;
  }
  setX1(pX1) {
    this.mX1 = pX1;
  }
  getX2() {
    return this.mX2;
  }
  setX2(pX2) {
    this.mX2 = pX2;
  }
  getY0() {
    return this.mY0;
  }
  setY0(pY0) {
    this.mY0 = pY0;
  }
  getY1() {
    return this.mY1;
  }
  setY1(pY1) {
    this.mY1 = pY1;
  }
  getY2() {
    return this.mY2;
  }
  setY2(pY2) {
    this.mY2 = pY2;
  }
  getZ0() {
    return this.mZ0;
  }
  setZ0(pZ0) {
    this.mZ0 = pZ0;
  }
  getZ1() {
    return this.mZ1;
  }
  setZ1(pZ1) {
    this.mZ1 = pZ1;
  }
  getZ2() {
    return this.mZ2;
  }
  setZ2(pZ2) {
    this.mZ2 = pZ2;
  }
  getElement(pRow, pColumn) {
    return this.Matrix[pRow][pColumn];
  }
  static createIdentity() {
    return new Matrix(1, 0, 0, 0, 1, 0, 0, 0, 1);
  }
  static createTranslation(pTranslationVector) {
    return new Matrix(1, 0, pTranslationVector.getX(), 0, 1, pTranslationVector.getY(), 0, 0, 1);
  }
  static createScale(pScaleVector) {
    return new Matrix(pScaleVector.getX(), 0, 0, 0, pScaleVector.getY(), 0, 0, 0, 1);
  }
  static createRotation(pRotationScalar) {
    return new Matrix(Math.cos(pRotationScalar), -Math.sin(pRotationScalar), 0, Math.sin(pRotationScalar), Math.cos(pRotationScalar), 0, 0, 0, 1);
  }
  multiply(pMatrix) {
    return new Matrix(this.getX0 * pMatrix.getX0, this.getX1 * pMatrix.getY0, this.getX2 * pMatrix.getZ0, this.getY0 * pMatrix.getX1, this.getY1 * pMatrix.getY1, this.getY2 * pMatrix.getZ1, this.getZ0 * pMatrix.getX2, this.getZ1 * pMatrix.getY2, this.getZ2 * pMatrix.getZ2);
  }

它必须通过的测试:

describe("Multiply", function() {
var rotation, scaleVector, translationVector, translationMatrix,
  scaleMatrix, rotationMatrix, scaleXTranslationMatrix, translationXScaleMatrix,
  chainedMatrix;
rotation = Math.PI / 2;
rotationMatrix = Matrix.createRotation(rotation);
scaleVector = new Vector(2, 2, 1);
scaleMatrix = Matrix.createScale(scaleVector);
translationVector = new Vector(10, 20, 1);
translationMatrix = Matrix.createTranslation(translationVector);

describe("Scale X Translate", function() {
  scaleXTranslationMatrix = scaleMatrix.multiply(translationMatrix);
  it("Element (0,0) Set", function() {
    expect(scaleXTranslationMatrix.getElement(0, 0)).toEqual(2);
  });

  it("Element (0,1) Set", function() {
    expect(scaleXTranslationMatrix.getElement(0, 1)).toEqual(0);
  });

  it("Element (0,2) Set", function() {
    expect(scaleXTranslationMatrix.getElement(0, 2)).toEqual(20);
  });

  it("Element (1,0) Set", function() {
    expect(scaleXTranslationMatrix.getElement(1, 0)).toEqual(0);
  });

  it("Element (1,1) Set", function() {
    expect(scaleXTranslationMatrix.getElement(1, 1)).toEqual(2);
  });

  it("Element (1,2) Set", function() {
    expect(scaleXTranslationMatrix.getElement(1, 2)).toEqual(40);
  });

  it("Element (2,0) Set", function() {
    expect(scaleXTranslationMatrix.getElement(2, 0)).toEqual(0);
  });

  it("Element (2,1) Set", function() {
    expect(scaleXTranslationMatrix.getElement(2, 1)).toEqual(0);
  });

  it("Element (2,2) Set", function() {
    expect(scaleXTranslationMatrix.getElement(2, 2)).toEqual(1);
  });
});

describe("Translate X Scale", function() {
  translationXScaleMatrix = translationMatrix.multiply(scaleMatrix);
  it("Element (0,0) Set", function() {
    expect(translationXScaleMatrix.getElement(0, 0)).toEqual(2);
  });

  it("Element (0,1) Set", function() {
    expect(translationXScaleMatrix.getElement(0, 1)).toEqual(0);
  });

  it("Element (0,2) Set", function() {
    expect(translationXScaleMatrix.getElement(0, 2)).toEqual(10);
  });

  it("Element (1,0) Set", function() {
    expect(translationXScaleMatrix.getElement(1, 0)).toEqual(0);
  });

  it("Element (1,1) Set", function() {
    expect(translationXScaleMatrix.getElement(1, 1)).toEqual(2);
  });

  it("Element (1,2) Set", function() {
    expect(translationXScaleMatrix.getElement(1, 2)).toEqual(20);
  });

  it("Element (2,0) Set", function() {
    expect(translationXScaleMatrix.getElement(2, 0)).toEqual(0);
  });

  it("Element (2,1) Set", function() {
    expect(translationXScaleMatrix.getElement(2, 1)).toEqual(0);
  });

  it("Element (2,2) Set", function() {
    expect(translationXScaleMatrix.getElement(2, 2)).toEqual(1);
  });
});

describe("Chaining", function() {
  var cosAngle, sinAngle;
  cosAngle = Math.cos(Math.PI / 2);
  sinAngle = Math.sin(Math.PI / 2);
  chainedMatrix =
    translationMatrix.multiply(scaleMatrix).multiply(rotationMatrix);
  it("Element (0,0) Set", function() {
    expect(chainedMatrix.getElement(0, 0)).toEqual(2 * cosAngle);
  });

  it("Element (0,1) Set", function() {
    expect(chainedMatrix.getElement(0, 1)).toEqual(2 * -sinAngle);
  });

  it("Element (0,2) Set", function() {
    expect(chainedMatrix.getElement(0, 2)).toEqual(10);
  });

  it("Element (1,0) Set", function() {
    expect(chainedMatrix.getElement(1, 0)).toEqual(2 * sinAngle);
  });

  it("Element (1,1) Set", function() {
    expect(chainedMatrix.getElement(1, 1)).toEqual(2 * cosAngle);
  });

  it("Element (1,2) Set", function() {
    expect(chainedMatrix.getElement(1, 2)).toEqual(20);
  });

  it("Element (2,0) Set", function() {
    expect(chainedMatrix.getElement(2, 0)).toEqual(0);
  });

  it("Element (2,1) Set", function() {
    expect(chainedMatrix.getElement(2, 1)).toEqual(0);
  });

  it("Element (2,2) Set", function() {
    expect(chainedMatrix.getElement(2, 2)).toEqual(1);
  });
});

});

});

我没有想法,所以任何形式的帮助都会很棒,谢谢。

【问题讨论】:

  • 包含 where 你得到错误而不是让人们使它可运行并弄清楚它可能是有益的。请查看How to Ask 页面。
  • 对不起,新的,当将两个矩阵相乘时发生错误,而不是产生一个整数,它会导致 NaN 错误。
  • 这还不够具体。您实际上是在让人们运行您的代码,以了解问题所在——这是非常值得期待的。

标签: javascript matrix matrix-multiplication


【解决方案1】:

您的 multiply 方法尝试将函数相乘,而不是数字:

multiply(pMatrix) {
  return new Matrix(
    this.getX0 * pMatrix.getX0,
    this.getX1 * pMatrix.getY0,
    this.getX2 * pMatrix.getZ0,
    this.getY0 * pMatrix.getX1,
    this.getY1 * pMatrix.getY1,
    this.getY2 * pMatrix.getZ1,
    this.getZ0 * pMatrix.getX2,
    this.getZ1 * pMatrix.getY2,
    this.getZ2 * pMatrix.getZ2
  );
}

这就是您得到NaN 的原因。更改代码以将数值相乘或调用 getter 函数:

multiply(pMatrix) {
  return new Matrix(
    this.getX0() * pMatrix.getX0(),
    this.getX1() * pMatrix.getY0(),
    this.getX2() * pMatrix.getZ0(),
    this.getY0() * pMatrix.getX1(),
    this.getY1() * pMatrix.getY1(),
    this.getY2() * pMatrix.getZ1(),
    this.getZ0() * pMatrix.getX2(),
    this.getZ1() * pMatrix.getY2(),
    this.getZ2() * pMatrix.getZ2()
  );
}

编辑:

您还更新了这些 getter 函数,因为它们试图获取未定义的属性。例如,getX0() 在内部返回 this.mX0。但this.mX0 从未设置,因此返回undefined

像这样改变你的 getter 函数:

...
getX0: function () {
  return this.getElement(0, 0);
}
...

您必须为每个 getter 执行此操作。另一种解决方案是在构造函数中调用相应的 setter 函数:

class Matrix {
  constructor(pX0, pX1, pX2, pY0, pY1, pY2, pZ0, pZ1, pZ2) {
    this.Matrix = [
      [pX0, pX1, pX2],
      [pY0, pY1, pY2],
      [pZ0, pZ1, pZ2]
    ];

    this.setX0(pX0);
    this.setX1(pX1);
    // ...
    this.setZ2(pZ2);
  }
  // ...
}

这是您的 Matrix 类的“固定”版本:

class Matrix {
  constructor(pX0, pX1, pX2, pY0, pY1, pY2, pZ0, pZ1, pZ2) {
    this.__matrix = [
      [pX0, pX1, pX2],
      [pY0, pY1, pY2],
      [pZ0, pZ1, pZ2]
    ];
  }
  getX0() {
    return this.getElement(0, 0);
  }
  setX0(pX0) {
    return this.setElement(0, 0, pX0);
  }
  getX1() {
    return this.getElement(0, 1);
  }
  setX1(pX1) {
    return this.setElement(0, 1, pX1);
  }
  getX2() {
    return this.getElement(0, 2);
  }
  setX2(pX2) {
    return this.setElement(0, 2, pX2);
  }
  getY0() {
    return this.getElement(1, 0);
  }
  setY0(pY0) {
    return this.setElement(1, 0, pY0);
  }
  getY1() {
    return this.getElement(1, 1);
  }
  setY1(pY1) {
    return this.setElement(1, 1, pY1);
  }
  getY2() {
    return this.getElement(1, 2);
  }
  setY2(pY2) {
    return this.setElement(1, 2, pY2);
  }
  getZ0() {
    return this.getElement(2, 0);
  }
  setZ0(pZ0) {
    return this.setElement(2, 0, pZ0);
  }
  getZ1() {
    return this.getElement(2, 1);
  }
  setZ1(pZ1) {
    return this.setElement(2, 1, pZ1);
  }
  getZ2() {
    return this.getElement(2, 2);
  }
  setZ2(pZ2) {
    return this.setElement(2, 2, pZ2);
  }
  getElement(pRow, pColumn) {
    return this.__matrix[pRow][pColumn];
  }
  setElement(pRow, pColumn, value) {
    this.__matrix[pRow][pColumn] = value;
    return this;
  }
  toString() {
    return `Matrix([${this.__matrix.reduce((acc, row) => acc + '[' + row.join(',') + ']', '')}])`;
  }
  static createIdentity() {
    return new Matrix(1, 0, 0, 0, 1, 0, 0, 0, 1);
  }
  static isIdentity(pMatrix) {
    return Matrix.prototype.isPrototypeOf(pMatrix) &&
           pMatrix.__matrix[0][0] === 1 &&
           pMatrix.__matrix[0][1] === 0 &&
           pMatrix.__matrix[0][2] === 0 &&
           pMatrix.__matrix[1][0] === 0 &&
           pMatrix.__matrix[1][1] === 1 &&
           pMatrix.__matrix[1][2] === 0 &&
           pMatrix.__matrix[2][0] === 0 &&
           pMatrix.__matrix[2][1] === 0 &&
           pMatrix.__matrix[2][2] === 1;
  }
  static createTranslation(pTranslationVector) {
    return new Matrix(
      1,
      0,
      pTranslationVector.getX(),
      0,
      1,
      pTranslationVector.getY(),
      0,
      0,
      1
    );
  }
  static createScale(pScaleVector) {
    return new Matrix(
      pScaleVector.getX(),
      0,
      0,
      0,
      pScaleVector.getY(),
      0,
      0,
      0,
      1
    );
  }
  static createRotation(pRotationScalar) {
    return new Matrix(
      Math.cos(pRotationScalar),
      -Math.sin(pRotationScalar),
      0,
      Math.sin(pRotationScalar),
      Math.cos(pRotationScalar),
      0,
      0,
      0,
      1
    );
  }
  multiply(pMatrix) {
    return new Matrix(
      this.getX0() * pMatrix.getX0(),
      this.getX1() * pMatrix.getY0(),
      this.getX2() * pMatrix.getZ0(),
      this.getY0() * pMatrix.getX1(),
      this.getY1() * pMatrix.getY1(),
      this.getY2() * pMatrix.getZ1(),
      this.getZ0() * pMatrix.getX2(),
      this.getZ1() * pMatrix.getY2(),
      this.getZ2() * pMatrix.getZ2()
    );
  }
}



// TEST
let m1 = new Matrix(1, 0, 0, 0, 1, 0, 0, 0, 1);
let m2 = Matrix.createIdentity();

let m3 = m1.multiply(m2); // should give us identity again

console.log(Matrix.isIdentity(m3)); // should log true
console.log(m3.toString());

【讨论】:

  • 尝试了您提供的第二段代码,仍然出现 NaN 错误,为任何方式的帮助欢呼
  • @david 用有效的实现更新了我的答案
  • 非常感谢,您帮了大忙。
猜你喜欢
  • 2015-01-15
  • 2018-04-11
  • 2017-03-11
  • 2013-12-23
  • 1970-01-01
  • 2014-09-19
  • 1970-01-01
相关资源
最近更新 更多