c – std :: pow对于不同的指数,行为非常不同

前端之家收集整理的这篇文章主要介绍了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 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,并且不愿错过一些完全无关紧要的事情.

谢谢!!

解决方法

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()实现;
>否则,请使用exponentiation by squaring approach.

必须通过仔细的基准测试找到用于在第一种和第二种方法之间进行选择的指数的边界值.

猜你在找的C&C++相关文章