【发布时间】:2016-06-27 17:47:16
【问题描述】:
我目前正在尝试优化一些代码,其中 50% 的时间花在 std::pow() 上。我知道指数将始终为正整数,而底数将始终为区间 (0, 1) 中的双精度数。为了好玩,我写了一个函数:
inline double int_pow(double base, int exponent)
{
double out = 1.0;
for(int i = 0; i < exponent; i++)
{
out *= base;
}
return out;
}
我正在编译:
> g++ fast-pow.cpp -O3 --std=c++11
我在 (0, 1) 之间生成了 1 亿个双精度,并比较了 (1) std::pow (2) 我自制的 int_pow 函数和 (3) 直接乘法的时序。这是我的计时程序的草图(这是一个非常快速的组合测试):
void time_me(int exp, size_t reps)
{
volatile double foo = 0.0;
double base = 0.0;
size_t i;
for (i = 0; i < reps; ++i)
{
base = ((double) rand() / (RAND_MAX)) + 1;
foo = pow(base, exp);
// foo = int_pow(base, exp);
// foo = base * base * base;
}
// check that the loop made it to the end
std::cout << foo << " " << i << std::endl;
}
int main()
{
std::clock_t start;
start = std::clock();
time_me(3, 1e8);
std::cout << "Time: " << (std::clock() - start) / (double)(CLOCKS_PER_SEC / 1000) << std::endl;
return 0;
}
以下是我观察到的各种指数的时间安排:
-
0:
std::pow0.71s,int_pow0.77s -
2:
std::pow1.31s,int_pow0.80s,直接乘法 0.86s -
3:
std::pow6.9s (!!),int_pow0.84s,直接多 0.76s - 5:类似于3:
我的问题
因此,我的问题是:
- 为什么
std::pow的性能在大于 2 的幂时会出现如此严重的下降? - 当提前知道基数或指数类型时,是否存在现有的更快的幂函数?
- 我忽略了一些完全明显的东西吗?对于已知整数指数的情况,我将通过直觉
std::pow,并且不愿意错过一些完全微不足道的事情。
谢谢!!
【问题讨论】:
-
您是否检查了编译器发出的机器指令,以确保它不会优化您的调用,因为您实际上并没有使用函数调用返回的值?
-
你能给我们你用来生成计时的实际代码吗?
-
pow函数可以欺骗 2 的幂并使用位移。对于其他幂,它可能会使用其指数算法。 -
@MAB -- Read this 在使用
pow对整数幂计算进行测试之前。 -
注意:pow 和 std::pow 的设计目的是像 e 到 pi 的力量一样做非常讨厌的工作。如果它没有像上面@ThomasMatthews 提到的那样便宜的黑客,它会退回到艰苦的工作上。 “当提前知道基数或指数类型时,是否存在现有的更快的幂函数?”指数类型是指值吗?如果值在编译时已知,请参见此处:stackoverflow.com/questions/16443682/…
标签: c++ performance numerical-methods