【问题标题】:operator precedence c++ | What is the exact order in which calculations are made?运算符优先级 c++ |计算的确切顺序是什么?
【发布时间】:2015-07-19 19:43:57
【问题描述】:

我正在尝试编写一个矩阵计算器,但遇到了一个困难。如果我有A = B*C,那么B*C 会使用我重载的operator*(const Matrix&) 进行评估,其中我需要一些临时对象来进行计算。这工作正常。但是一旦我遇到更复杂的东西,我需要更多的临时对象,显然我不想手动/有一个混合。

说我要评估:

Matrix A = B*C + D*E*F + G*H;

然后运算符优先级告诉我,* 将首先被评估。所以:

Step 1) B*C -> t1
Step 2) D*E -> t2
Step 3) t2*F-> t3
Step 4) G*H -> t4
Step 5) t1+t2 -> t5
Step 6) t5+t4 -> t6
Step 7) A=t6

这是确切的顺序吗?还是顺序不确定?我的想法是创建一个链表,我将检查我的 + 和 *,如果正在计算的对象(例如 t2*F)是临时的,那么我可以适当地删除/插入它们。

【问题讨论】:

  • 我不知道您对链表的要求是什么,但未指定确切的评估顺序。 B*C 将在 + 之前进行评估,但您不能假设 B*CD*E*FG*H 之前排序。
  • 您有两个问题,然后是您想要做什么的陈述。您试图解决的感知问题是什么?是否取决于您对问题的回答?

标签: c++ operator-keyword operator-precedence


【解决方案1】:

运算符优先级告诉您以什么顺序计算事物。它告诉您每个运算符的操作数是什么。

求值顺序的唯一保证是运算符的操作数必须先求值,然后该运算符才能进行运算。

看一个更简单的例子,2 + 3 * 4,优先级表示添加到2 的东西是3 * 4,而不是3


在您的示例B*C + D*E*F + G*H 中,唯一的保证是:

  • G*H 在第二个 + 之前评估
  • B*C 在第一个 + 之前评估
  • D*E*F+ 之前进行评估
  • 第一个 + 在第二个 + 之前进行评估
  • D*E*F 内,第一个* 在第二个* 之前计算。

可能的排序可能是:

(1) D*E
(2) G*H
(3) B*C
(4) 1*F
(5) 3+4
(6) 5+2

另请注意,如果BC 等本身需要任何评估,那么这些评估也没有任何相对顺序。

【讨论】:

  • 注意:我的回答回答了您标题中的问题,尽管“问题的根源”似乎是您想要消除临时对象;这实际上与评估顺序无关。您的“链表”实际上应该是一棵树,只要您正确设置了树结构,您遍历树的顺序并不重要。
  • 树比表达式模板更容易编码,但在代码中更难使用
【解决方案2】:

Expression templates可以解决这个问题。例如

Matrix M = 2*(A+B) + C;

通常会为A+B2*(A+B)2*(A+B) + C 创建 3 个临时对象。因此,当 Matrix 对象是重量级时,这可能会变得低效。

表达式模板是一种模板元编程技术,其中运算符被实现为返回一个表示整个表达式的对象,但仅在末尾计算表达式。

所以2*(A+B) + C 会产生一个类似的对象

sum<multiple<float, sum<Matrix, Matrix>>, Matrix>

它能够在不分配中间矩阵的情况下计算M。 (在这种情况下,通过按分量加法和乘以常数)。该对象本身以零运行时开销生成。

因为这很复杂,所以最好使用线性代数库,例如Eigen

【讨论】:

  • 请注意,右值引用可以减少需要创建的临时对象的数量,但不能减少循环的数量。表达式模板是获得良好缓存行为的正确方法。
【解决方案3】:

我的想法是创建一个链表,我将检查我的 + 和 *, 如果正在计算的对象(例如 t2*F)是临时的, 然后我可以适当地删除它们/插入。

不要。
这完全没有意义,只会带来额外的问题。大时代。

编译器可以为您处理所有事情,您可以放心地依赖它。 C++ 不是汇编程序级别的。只需返回临时的基于堆栈的对象(没有指针或任何东西)。您计算的中间结果将自行清理。

Matrix operator+(const Matrix&) {...}  
Matrix operator*(const Matrix&) {...}  

每个这样的函数都有一个临时对象 insde 来计算,然后返回。
这就是你需要的一切。

【讨论】:

  • 对于大型矩阵,组合运算当然是有意义的,在更少的循环中执行更多的计算。
猜你喜欢
  • 2017-10-13
  • 1970-01-01
  • 2011-10-25
  • 2018-06-21
  • 1970-01-01
  • 1970-01-01
  • 2012-08-21
相关资源
最近更新 更多