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 :: pow 0.71s,int_pow 0.77s
> 2:std :: pow 1.31s,int_pow 0.80s,direct mult 0.86s
> 3:std :: pow 6.9s(!!),int_pow 0.84s,直接多重0.76s
> 5:类似于3:
我的问题
所以有了这个,我的问题是:
>对于大于2的幂,为什么std :: pow的性能会降低得如此糟糕?
>当基本或指数类型提前知道时,是否存在更快的幂函数?
>有什么东西是我忽略的吗?对于已知整数指数的情况,我即将通过gut std :: pow,并且不愿错过一些完全无关紧要的事情.
谢谢!!
解决方法
sysdeps/ieee754/dbl-64/e_pow.c:
double __ieee754_pow (double x,double y) { ... ... if (y == 1.0) return x; if (y == 2.0) return x * x; if (y == -1.0) return 1.0 / x; if (y == 0) return 1.0;
正如您所看到的,指数值0,1和-1也是专门处理的,但至少这些是数学上重要的特殊情况,而平方仅仅是一个统计上显着的情况,否则不值得特殊处理).编辑:指数值0,1,2和-1是唯一允许用(更快)算术运算表达std :: pow(x,n)而没有任何精度损失的值.有关详细信息,请参见this answer.因此,指数值2不仅仅是统计上显着的情况.结束编辑
如果你想要std :: pow()的快速替代指数的非负整数值而不关心轻微的精度损失,那么
>对于指数的足够小的值,使用你的int_pow()实现;
>否则,请使用exponentiation by squaring approach.
必须通过仔细的基准测试找到用于在第一种和第二种方法之间进行选择的指数的边界值.