在 C/C++ 中,你可以设置如下的代码:
double a, b, c;
...
c = (a + b) / 2;
这与以下代码执行的功能完全相同:
c = (a + b) * 0.5;
我想知道使用哪个更好。这两种操作中,有一种基本上比另一种更快吗?
在 C/C++ 中,你可以设置如下的代码:
double a, b, c;
...
c = (a + b) / 2;
这与以下代码执行的功能完全相同:
c = (a + b) * 0.5;
我想知道使用哪个更好。这两种操作中,有一种基本上比另一种更快吗?
乘法比除法快。在大学里我学到的是除法需要六倍于乘法的时间。实际的计时取决于体系结构,但通常情况下乘法永远不会比除法慢甚至同样慢。如果舍入误差允许,请始终将代码优化为使用乘法。
所以在一个例子中,这通常会更慢......
for (int i=0; i<arraySize; i++) {
a[i] = b[i] / x;
}
比这个更......
y=1/x;
for (int i=0; i<arraySize; i++) {
a[i] = b[i] * y;
}
当然,使用第二种方法会有舍入误差,你会失去一些精度,但除非你不断地计算 x=1/x;
,否则这不太可能引起太多问题。如果编译器“认为”这样更快,那么在这种情况下,编译器很可能会将除法转换为乘法。在浮点数除以2时,也可能比其他浮点数除法更快。如果编译器没有进行转换,则使用乘法可能会更快,但不确定-这取决于处理器本身。
在编译器无法确定是否安全的情况下(例如0.1不能在浮点数中准确存储为0.1,而是变成了0.10000000149011612),手动使用乘法而不是除法可以获得相当大的收益。请参见下面有关代表该类别的AMD处理器的数据。
要判断编译器是否处理得好,为什么不编写一些代码进行实验呢?确保将代码编写为使编译器不仅计算常量值并且在循环中放弃所有计算。
编辑:
AMD Family 15h处理器的优化指南提供了fdiv
和fmul
的数据,分别为42和6。SSE版本稍微接近,DIVPS、DIVPD、DIVSS和DIVSD(除法)的时钟周期分别为24(单精度)或27(双精度),所有形式的乘法都需要6个时钟周期。
据我记忆,英特尔的数据差不多。
0.1
的说法。 - jason浮点数乘法通常比浮点数除法需要更少的周期。但是对于字面操作数,优化器非常清楚这种微小的优化。
x/y —> x * (1/y)
受-ffast-math
许可。具体来说,这是由-ffast-math
中包含的“优化”之一 -freciprocal-math
许可的。 - Stephen Canon