【问题标题】:Define a Matlab-like .* operator in C++?在 C++ 中定义类似 Matlab 的 .* 运算符?
【发布时间】:2012-08-06 00:04:48
【问题描述】:

Matlab 能够用不同的运算符区分“正确”矩阵乘法和逐元素矩阵乘法,因此前者以A * B 完成,后者以A .* B 完成。这非常方便,我想知道是否有一种方法可以在 C++ 中为自定义矩阵类实现相同的功能(同样适用于./.^)。也就是说,我想知道是否有可能通过定义宏或任何其他方法来实际编译如下内容:

MyMatrix A(2,3), B(2,3), C(2,3); //These are 2x3 matrices for the sake of concreteness
C = A .* B; //Similarly for ./, .^

我尝试用一​​些简单的函数#defines 来做这件事,但无法让它工作,所以我想我会把它交给 SO。我可以接受“未遂事件”,即如果 .* 不能工作,但不知何故 :* 可以,就够了。注意,我专门寻找运算符——当然,这种行为可以通过函数以显而易见的方式完成,但类似 ​​Matlab 的运算符会非常方便。

【问题讨论】:

  • 如果您发现这个“非常方便”,您显然没有将矩阵用于“正常”目的——线性运算符,* 作为组合——而是用于其他东西,其中*因为矩阵乘法可能没有太大意义。所以你可能想要两个不同的类,一个用于线性映射矩阵,一个用于元素矩阵,每个都有自己的operator*。如果您需要从一种表示形式转换到另一种表示形式,您可以添加显式或隐式转换函数。这样,它不仅会更不言自明,而且比 Matlab 版本更安全。
  • @leftaroundabout 你熟悉 Matlab 吗?正如我所描述的那样,这种情况存在。无论如何,在大量使用 Matlab(和矩阵)之后,在某些情况下,对于给定的矩阵,您有时会想要对其进行标准矩阵乘法,而在另一种情况下,会进行一些元素操作.所以这会很方便。
  • 据我所知,matlab中的.*是做与矩阵乘法不同的标量乘法。在 C++ 中,您完全可以使用一个运算符 * 并进行运算符/函数重载。
  • 嗯,这样的东西在 Matlab 中可以很方便并不奇怪,因为 Matlab 的重点是“一切都是矩阵”(恕我直言,数学上没有吸引力的观点:矩阵非常方便,但不是很多为了他们自己的利益,但为了表示更抽象的概念)。这不一定是好事。即使你有一个矩阵在一个点参与矩阵乘法,而在另一个点参与元素乘法,你要乘的矩阵 with 几乎肯定有完全不同的含义,因此应该有不同的类型.

标签: c++ matlab operators


【解决方案1】:

这是一种与 Managu 的回答类似的技术,只是不使用宏......

struct Mat;
struct EleWise {
  EleWise(){}
  double mat[3][3];
};

struct Mat {
  Mat(){}

  friend Mat operator / ( EleWise& e, const Mat& m ) 
  { 
     return Mat(); // perform elewise divide
  }
  EleWise _;
};


int main( int argc, char** arg ) {
  Mat a;
  Mat b;

  Mat c = a ._/ b;
  return 0;
};

【讨论】:

    【解决方案2】:

    并不是说我真的建议这样做(这是可憎的)。比如说,你可以创建一个小的包装类,当它乘以一个矩阵时,它会执行一个元素乘法。然后给矩阵类一个element_wise()方法,它返回这样一个包装器。然后,您冷“创建”运算符_*_/ 等:

    #define _ .element_wise()
    
    A = B _* C; // really B.element_wise() * C
    

    或者通过在构造时给每个矩阵一个这样的包装器并将其称为_,从而使预处理器远离它,从而允许:

    A = B ._* C;
    B = A ._/ C;
    

    【讨论】:

    • 这是一个可怕的建议。宏几乎从来都不是要走的路,将_ 定义为宏是自找麻烦。特别是,我将_ 用于不关心参数,这个宏会以许多不同的方式破坏我的代码。
    • @David Rodríguez - dribeas hist 的回答不是以“我不是真的建议这样做”开头吗?这是一个假设的解决方案。真的,如果你的代码被这个宏破坏了,这真的不是这个宏的问题:)
    • @RodyOldenhuis:宏会破坏代码,问题是如果定义了这样的宏,一些完美运行的代码将停止工作。您可能不认为这是一个问题,但认为我可以 #define i *complex<double>(0.,1.) 使代码更像数学:complex<double> a = 5 i; 如果您使用 i 作为变量是您的问题...我的宏很好! #define T typedef 怎么样,它让我的类型定义更好!说真的,一般情况下应该避免使用宏,而没有遵循约定的名称(全部大写,长名称)的宏更是如此。
    • @David Rodríguez - dribeas 你在描述掩蔽。这不是宏独有的问题,即,当包含具有相同类名和签名等的两个不同库时,也会发生屏蔽。不同之处在于,在后一种情况下,编译器更容易出现此类问题。你不喜欢宏,我也一样。但是你应该讨厌它们,因为它们更有可能引入错误,而不是因为它们会破坏代码。这是 您的代码 的问题,而不是一般宏的问题。
    • @RodyOldenhuis:宏的问题是它们不尊重其余代码,这与一般的 masking 问题不同,因为我可以将我的代码放在我自己的命名空间中,这样第三方库中定义的符号就不会影响我的代码。但是这些库中的 macros 会破坏系统其他部分的代码。你可能不认为这是一个问题,但如果你用谷歌搜索宏问题,我敢打赌,他们建议不使用宏的大多数地方是因为它们会破坏其他引入错误的代码。
    猜你喜欢
    • 2010-10-06
    • 1970-01-01
    • 2013-11-07
    • 2011-11-26
    • 1970-01-01
    • 2019-01-02
    • 1970-01-01
    • 1970-01-01
    • 2015-06-05
    相关资源
    最近更新 更多