算子链,为什么要长左枝
Operator chaining, why grow left branch?
本文关键字:为什么 更新时间:2023-10-16
根据这个问题(即OP陈述了信念并且没有被纠正) - 链式运算符向左增长:
a << b << c << d;
// ==
operator<<( operator<<( operator<<(a, b), c ), d);
为什么会这样呢?这样做不是更有效率吗:
operator<<( operator<<(a, b), operator<<(c, d) );
即,尽可能平衡?
编译器当然可以解决这个问题以获得更好的运行时性能吗?
在 C++ 中重载运算符时,它保留与运算符未重载时相同的优先级和关联性。
对于轮班操作员(<<
和>>
),标准要求:
轮班操作员从左到右<<和>>分组。
这意味着像 a<<b<<c
这样的操作必须解析为 (a<<b)<<c
。
重载运算符会更改为每个操作调用的代码,但对分组没有影响 - 无论a
、b
和c
是将使用编译器提供的运算符的内置类型(例如,int
),或者它们是否是将使用重载运算符的某种类类型,分组都将相同。无论哪种方式,处理分组的解析器都保持不变。
但请注意,计算顺序与优先级或关联性无关,因此这不一定影响执行速度。
- 通过将
- 转换操作转换为 CISC,可以更好地实现"更好的运行时性能"。(例如 MULADDs。
- 两个处理器之间的同步成本将远远超过挤在一条生产线上的任何合理数量的操作员的好处。
- 这将使无序处理无法有效地使每个内核以奔腾 Pro 的速度运行。
- 除了 Mystical 提到的
std::cout
之外,想想下面的整数算术问题:3 * 5 / 2 * 4
应该导致(15 / 2) * 4
,意思是28
,但如果拆分出来,它会导致15 / 8
,意思是1
。即使运算符具有相同的意义,也是如此。
编辑:
很容易认为我们可以侥幸在内核之间拆分交换操作,例如3 * 5 * 2 * 4
.
现在让我们考虑一下,在内核之间进行通信的唯一方法是通过共享内存。并且平均加载时间比平均 CPU 运行时间慢一个数量级。仅此一项就意味着在容纳 1 个负载之前需要完成大量的数学运算。但更糟糕的是:
- 主核心必须将要执行的数据和操作写入内存。由于它们必须是分开的,因此写入时可能会出现页面错误。
- 主内核完成后,它必须加载一个脏位来检查从内核是否已完成处理。它可能正忙或已被抢占,因此这可能需要多个负载。
- 然后必须加载来自从机核心的结果。
你可以看到考虑到负载的费用,这会有多糟糕。让我们看一下如果所有内容都保留在一个内核上可以完成的优化:
- 如果提前知道某些值,则可以将它们分解为2s,并且可以进行偏移。更好的班次和添加可能一次执行超过 1 个操作。
- 对于 32 位或更小的数字,可以使用 64 位处理器的上位和下位进行加法。
-
无序处理可以由 CPU 自行决定,例如浮点运算比整数运算慢,因此在以下情况下:1.2 * 3 * 4 * 5
CPU 将首先执行3 * 4 * 5
,并且只执行 1 个浮点操作。
相关文章:
- 为什么"do while"循环不断退出,即使条件计算结果为 false?
- 为什么在全局范围内使用"extern int a"似乎不行?
- 为什么在popback()操作之后,它仍然打印完整的矢量
- 为什么随机数生成器不在void函数中随机化数字,而在main函数中随机化
- 为什么两个不同的未命名名称空间可以共存于一个cpp文件中
- 为什么会发生堆损坏
- 为什么使用 "this" 指针调用派生成员函数?
- C++我的数学有什么问题,为什么我的代码不能正确循环
- 为什么比较运算符如此快速
- 为什么 Serial.println(<char[]>);返回随机字符?
- 为什么这个运算符<重载函数对 STL 算法不可见?
- 为什么不;名字在地图上是按顺序排列的吗
- 我的字符计数代码计算错误.为什么
- 为什么在没有显式默认构造函数的情况下,将另一个结构封装在联合中作为成员的结构不能编译
- 为什么我的C#代码在调用回C++COM直到Task时会暂停.等待/线程.加入
- 为什么在C++中使用私有复制构造函数与删除复制构造函数
- 为什么野牛仍在使用"int yylex(void)",却找不到"int yylex(YYS
- 为什么 std::unique 不调用 std::sort?
- 既然存在危险,为什么项目要使用-I include开关
- 为什么在运行时没有向我们提供有关分段错误的更多信息?