为什么c中的功率功能需要比预期更长的时间

时间:2015-02-08 05:45:53

标签: c++ c

我在哪里弄错了? c / c ++中的pow(double,double)函数在O(log n)时间运行,这意味着它不应该花费很长时间来计算长数的幂。我写了一个函数来计算对数时间的a ^ b mod m,这个时间也比预期的要长。 该函数定义为:

float pow(float a,float n,float m){
  float temp,temp2;
  if(n==0)
    return 1;
  temp=pow(a,n/2,m);
  if(fmod(n,2)==0){
    if(temp>m){
      temp=fmod(temp,m);
    }
    temp2=temp*temp;
    if(temp2>m)
      temp2=fmod(temp2,m);
    return temp2;
  }
  else{
    if(temp>m){
      temp=fmod(temp,m);
    }
    temp2=temp*temp*a;
    if(temp2>m)
      temp2=fmod(temp2,m);
    return temp2;
  }
}

如果我打电话给pow(10 ^ 9,10 ^ 9,123)我希望它以~O(log(10 ^ 9))复杂度运行,因此在我的电脑上完成不到1秒(O(10 ^ 8)在1秒内运行)。但它的表现就像永远。与std :: pow(double,double)相同。

2 个答案:

答案 0 :(得分:2)

因此,重复将浮点数除以2只会在指数用尽时完成。 (为了好玩,尝试传入1.0f/0.0f。)

int func(float n) {
    if (n == 0)
        return 1;
    return 1 + func(n / 2);
}

在我的系统上,func(1.0f)给出151.这可能不是你想要的!

你想要这个:

float pow(float a, int n, float m) {
    if (n == 0)
        return 1.0f;
    float t = pow(a, n / 2, m);
    return fmodf((n & 1) ? t*t*a : t*t, m);
}

请注意pow()完全不同。 pow()的定义更接近于此:

float powf(float x, float y) {
    if (...) {
        // faster, special case versions
    }
    return expf(logf(x) * y);
}

答案 1 :(得分:0)

结束递归的唯一条件是n为零。只有连续除以2得到零结果(这基本上意味着浮动类型的下溢)才能实现。这需要一段时间才能获得大值。