我想知道以下两种方法之间的速度是否存在差异
#include<math.h>
#include<iostream>
using namespace std;
int main()
{
float k=7;
float b=4;
cout<<(float)k/b<<" "<<endl;
cout<<(float)(k*powf(b,-1))<<" "<<endl;
return 0;
}
k/b
k*b^(-1)
,我认为在第二种方法中,没有实际的划分程序。所以我认为第二个更快。我是对的吗?
答案 0 :(得分:4)
你错了很可能很好。即使编译器可以生成powf
作为内在函数(即,为它生成内联代码),N -1 相当于1 / N,所以你只是在进行划分更迂回的时尚。如果提高功率是一种更快的分割方式,那么编译器可能已经生成了代码来实现这种方式。
另一方面,如果你使用相同的分母进行大量的划分,你可以 通过转动循环来获得某些东西:
for (int i=0; i<some_size; i++)
somearray[i] /= denom;
成:
double scale = 1.0/denom;
for (int i=0; i<some_size; i++)
somearray[i] *= scale;
当然,编译器可能也足够聪明,但至少在这样的事情上,你正在做的事情有可能成为一种改进 - 唯一问题是编译器是否已经为你做了它。
答案 1 :(得分:2)
你应该对这两个版本进行分析并检查哪一个版本更快,但是如果它是第二个,我几乎准备好吃我的帽子了,原因如下:
powf
是一个通用函数,对于exponent参数的典型值,非常慢。即使它被优化以专门处理案例-1
,仍然会有if
等,检查这种特殊情况,这将增加计算的开销。powf
可能没有内联,您将承担函数调用的费用。k*(1.0/b)
真的比k/b
快,那么编译器会将后者优化为前者(特别是在指定编译器标志以允许快速但不一定完全符合IEEE标准的浮动时)点数学。)最重要的是,现代编译器非常擅长进行微优化;我不会梦想像这样的尝试“技巧”,除非分析和反汇编显示出明确的证据表明编译器正在做一些低效的事情。
答案 2 :(得分:1)
速度总是取决于编译器的优化程度。因此,只有通过测量才能找到可靠的答案。
然而,第二种方法意味着比第一种方法更多的呼叫。因此,我猜第一个会更快。
答案 3 :(得分:1)
计算b ^( - 1)并不简单,有时(但并不总是)由优化器转换为1 / b。同样,优化程序可能会将*b^(-1)
切换为/b
。这可能与硬件有关(如果在编译时已知数字,则可能与数字有关)。
如果你想测试它,把每一个放在一个多次运行的循环中(不要在屏幕上打印任何东西),并在每次执行时计时。
另请注意,在某些情况下,如果您对精确计算感兴趣,这两种方法会给您略微不同的结果。
答案 4 :(得分:1)
正如其他人所述,简介。 在计算机科学中,可以通过重复减法来实现除法。这可能比乘以逆更快。
我认为除法必须比倒数更快,因为必须首先计算逆,然后执行乘法。因此,虽然除法正在执行减法,但另一种方法是确定逆。在计算逆之后,必须执行多次移位和加法(乘法)。
答案 5 :(得分:1)
在我的x86-64机器上使用gcc -O2,k / b转换为一条指令:
divss xmm0, xmm1
'powf'方式导致以下结果:
movss xmm2, DWORD PTR .LC0[rip]
divss xmm2, xmm1
mulss xmm2, xmm0
movaps xmm0, xmm2
其中.LC0是1065353216,或1.0f。
所以在我看来,至少对于现在常见的x86-64机器来说,k / b更快。