c – std :: pow对于不同的指数,行为非常不同
我目前正在尝试优化一些代码,其中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 :: pow 0.71s,int_pow 0.77s 我的问题 所以有了这个,我的问题是: >对于大于2的幂,为什么std :: pow的性能会降低得如此糟糕? 谢谢!! 解决方法
std :: pow()是一个通用函数,用于接受任何一对浮点值.它执行昂贵的计算,应该被认为是一个缓慢的功能.然而,显然,很多人已经滥用它进行平方,因此在IBM Accurate Mathematical Library(由glibc使用)中执行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()实现; 必须通过仔细的基准测试找到用于在第一种和第二种方法之间进行选择的指数的边界值. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |