-2

我想知道以下两种方法在速度上是否有区别

#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;
}
  1. 琐碎的划分k/b
  2. 使用乘法k*b^(-1)

我认为在第二种方法中,没有实际的划分程序。所以我认为第二个更快。我对吗?

4

6 回答 6

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;

当然,编译器可能也足够聪明,可以做到这一点,但至少在这样的情况下,你正在做的事情很有可能成为改进——唯一的问题是编译器是否已经这样做了它给你。

于 2012-04-16T19:18:28.280 回答
2

您应该分析两个版本并检查哪个版本更快,但如果是第二个版本,我几乎准备吃掉我的帽子,原因如下:

  1. powf是一个通用函数,对于指数参数的典型值来说非常慢。即使经过优化-1专门处理这种情况,仍然会有ifs 等来检查这种特殊情况,这会增加计算的开销。
  2. 根据实现,powf可能不会内联,并且您将承担函数调用的成本。
  3. 如果k*(1.0/b)真的比 快k/b,那么编译器已经将后者优化为前者(尤其是在指定编译器标志以允许快速但不一定完全符合 IEEE 的浮点数学时。)

底线是现代编译器非常擅长执行微优化。我不会梦想尝试像这样的“技巧”,除非分析和反汇编显示明确的证据表明编译器正在做一些低效的事情。

于 2012-04-16T19:20:28.297 回答
1

速度始终取决于编译器的优化程度。所以,只有通过测量才能找到可靠的答案。

但是,第二种方法比第一种方法意味着更多的调用。因此,我想第一个会更快。

于 2012-04-16T19:15:58.927 回答
1

计算 b^(-1) 并非易事,有时(尽管不总是)会被优化器转换为 1/b。同样,优化器可能会*b^(-1)使用/b. 这可能与硬件有关(如果在编译时已知数字,甚至可能与数字有关)。

如果你想测试它,把每一个都放在一个运行多次的循环中(不要在屏幕上打印任何东西),并为每次执行计时。

另请注意,在某些情况下,如果您对精确计算感兴趣,这两种方法会给您带来略微不同的结果。

于 2012-04-16T19:17:48.457 回答
1

正如其他人所说,个人资料。在计算机科学中,除法可以通过重复减法来实现。这可能比乘以倒数更快。

我相信除法会比乘以倒数更快,因为必须先计算倒数,然后再执行乘法。因此,当除法执行减法时,另一种方法是确定逆。在计算出逆后,必须执行多次移位和加法(乘法)。

参见关于除法算法的维基百科文章

于 2012-04-16T19:25:20.403 回答
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 更快。

于 2012-04-16T19:33:03.703 回答