乘法比浮动除法快吗?

wod*_*uck 71 c c++ optimization performance

在C/C++中,您可以设置以下代码:

double a, b, c;
...
c = (a + b) / 2;
Run Code Online (Sandbox Code Playgroud)

这与以下内容完全相同:

c = (a + b) * 0.5;
Run Code Online (Sandbox Code Playgroud)

我想知道哪个更好用.一项业务从根本上比另一项更快吗?

Phi*_*ing 37

乘法比除法更快.在大学时,我被教导说,除法是乘法的六倍.实际时序取决于体系结构,但一般来说,乘法永远不会慢,甚至像分裂一样慢.如果舍入误差允许,请始终优化代码以使用乘法.

所以在一个例子中,这通常会更慢......

for (int i=0; i<arraySize; i++) {
    a[i] = b[i] / x;
}
Run Code Online (Sandbox Code Playgroud)

... 比这个 ...

y=1/x;
for (int i=0; i<arraySize; i++) {
    a[i] = b[i] * y;
}
Run Code Online (Sandbox Code Playgroud)

当然,对于舍入误差,您将使用第二种方法松散(一点点)精度,但除非您反复计算x=1/x;这不太可能导致太多问题.

编辑:

仅供参考.我通过在Google上搜索来挖掘第三方对操作时间的比较.

http://gmplib.org/~tege/x86-timing.pdf

查看MUL和DIV上的数字.这表示5到10倍之间的差异,具体取决于处理器.

  • "*无法理解为什么这个被投票如此之多*"因为在任何问题上,即使是未定义/未指定/依赖于实现的行为,也可能会立即被低估,关闭和扫地.显然,迂腐比现实和务实的发展需要更有意义.略带舌头,但有时候会有这种感觉. (25认同)
  • @Thomas:我猜这个问题来自于这个问题非常简单并且具有完全重复的事实,它自动显示在右边的"相关"列中(读作:没有研究工作),优化很高过早的可能性(想想乱序执行和内存带宽),并且代码片段包含隐式的双重转换和与问题无关的额外操作.(那只是一个猜测,当然,我不是一个贬低者,所以说不出来) (8认同)
  • @Thomas是的.令人痛苦的是,这甚至不含糊或不明确.处理器制造商通常会公布统计数据.这是统计数据来源于编译器执行优化的地方.所以这里"未定义"的意思是"我还没读过".aaarrrrrrr.好的.</咆哮> (4认同)
  • 有关x86,请参阅http://agner.org/optimize/.div和mul具有不同的吞吐量与延迟的比率.两者都只有1个uop,因此可以与其他操作重叠.你的吞吐量看起来要贵6倍左右,但这些天FP div的延迟比更像是4(在Intel Haswell上).英特尔Skylake有一个非常流水线的FP div单元(每4个周期产生一个双倍的吞吐量).(256b SIMD向量具有较低的吞吐量). (3认同)

oua*_*uah 25

浮点乘法通常比浮点除法占用更少的周期.但是对于文字操作数,优化器很清楚这种微优化.

  • 如果我们在问题中询问除单个示例之外的案例,那么我们就不能依赖于优化器.除以2的幂除以乘以逆是等价的二进制浮点,但是其他因子的除法没有等效的乘法,因为倒数不能精确表示.这禁止优化器进行转换.因此,程序员应该意识到这一点,并且如果他们知道逆的舍入误差是可接受的,则应该有利于乘法. (23认同)
  • `x/y - > x*(1/y)`由`-ffast-math`许可.具体来说,这是由`-freciprocal-math`许可的,这是`-ffast-math`中包含的"优化"之一. (18认同)

Mat*_*son 23

在这种情况下,编译器很可能会将除法转换为乘法,如果它"认为"它更快.在浮点中除以2也可能比其他浮点除法更快.如果编译器没有转换它,使用乘法可能会更快,但不确定 - 取决于处理器本身.

在编译器无法确定这样做是"安全"的情况下,手动使用乘法而不是除法的增益可能非常大(例如,0.1在浮点数中不能精确地存储为0.1,它变为0.10000000149011612 ).有关AMD处理器的数据,请参见下文,可以将其视为该类的代表.

要判断你的编译器是否做得好,为什么不编写一些代码来进行实验.确保你编写它,以便编译器不只是计算一个常量值并丢弃循环中的所有计算.

编辑:

AMD的优化指南家庭15小时处理器,提供数字fdivfmul-分别为42和6.对于DIVPS,DIVPD DIVSS和DIVSD(除法),SSE版本更接近,24(单)或27(双)周期,并且对于所有形式的乘法,6个周期.

从内存来看,英特尔的数据并不遥远.

  • 我现在遇到了什么错误,我因为提供更多信息而被投票?请告诉我,这样我就可以学习! (2认同)
  • 不太清楚您在第二段中的意思(括号永远不会关闭,并且句子有点拖尾。但正如其他答案的评论中所指出的那样,编译器通常不会在以下情况下将除法转换为乘法处理浮点代码。 (2认同)