自制的pow()c ++

gar*_*n06 8 c++ math

我正在阅读如何自己编写电源功能?dan04给出的答案引起了我的注意,主要是因为我不确定fortran给出的答案,但我接受了并实现了这个:

#include <iostream>
using namespace std;
float pow(float base, float ex){
    // power of 0
    if (ex == 0){
        return 1;
    // negative exponenet
    }else if( ex < 0){
        return 1 / pow(base, -ex);
    // even exponenet
    }else if ((int)ex % 2 == 0){
        float half_pow = pow(base, ex/2);
        return half_pow * half_pow;
    //integer exponenet
    }else{
        return base * pow(base, ex - 1);
    }
}
int main(){
    for (int ii = 0; ii< 10; ii++){\
        cout << "pow(" << ii << ".5) = " << pow(ii, .5) << endl;
        cout << "pow(" << ii << ",2) = " << pow(ii,  2) << endl;
        cout << "pow(" << ii << ",3) = " << pow(ii,  3) << endl;
    }
}
Run Code Online (Sandbox Code Playgroud)

虽然我不确定我是否正确翻译,因为所有的调用都给.5作为指数返回0.在答案中它说明它可能需要一个log2(x)基于a^b = 2^(b * log2(a)),但我不确定是否将其放入我不确定把它放在哪里,或者我是否正在考虑这个问题.

注意:我知道这可能是在数学库中定义的,但是我不需要为一些函数增加整个数学库的所有费用.

编辑:有没有人知道分数指数的浮点实现?(我已经看过一个双重实现,但那是使用了一个带寄存器的技巧,我需要浮点数,并添加一个库只是为了做一个技巧我会更好,只包括数学库)

Sir*_*Guy 7

我在这里看了这篇论文,它描述了如何近似指数函数的双精度.在对维基百科进行了一些关于单精度浮点表示的研究后,我得出了等效的算法.他们只实现了exp函数,所以我找到了日志的反函数,然后就完成了

    POW(a, b) = EXP(LOG(a) * b).
Run Code Online (Sandbox Code Playgroud)

编译这个gcc4.6.2产生的pow函数几乎比标准库的实现快4倍(用O2编译).

注意:EXP的代码几乎是从我读过的文件中逐字复制的,LOG函数是从这里复制的.

这是相关代码:

    #define EXP_A 184
    #define EXP_C 16249 

    float EXP(float y)
    {
      union
      {
        float d;
        struct
        {
    #ifdef LITTLE_ENDIAN
          short j, i;
    #else
          short i, j;
    #endif
        } n;
      } eco;
      eco.n.i = EXP_A*(y) + (EXP_C);
      eco.n.j = 0;
      return eco.d;
    }

    float LOG(float y)
    {
      int * nTemp = (int*)&y;
      y = (*nTemp) >> 16;
      return (y - EXP_C) / EXP_A;
    }

    float POW(float b, float p)
    {
      return EXP(LOG(b) * p);
    }
Run Code Online (Sandbox Code Playgroud)

你可以在这里做一些优化,或者也许这已经足够好了.这是一个粗略的近似,但如果您对使用双重表示引入的错误感到满意,我想这将是令人满意的.


Cap*_*liC 5

我认为您正在寻找的算法可能是“第 n 个根”。初始猜测为 1(对于 k == 0):

#include <iostream>
using namespace std;


float pow(float base, float ex);

float nth_root(float A, int n) {
    const int K = 6;
    float x[K] = {1};
    for (int k = 0; k < K - 1; k++)
        x[k + 1] = (1.0 / n) * ((n - 1) * x[k] + A / pow(x[k], n - 1));
    return x[K-1];
}

float pow(float base, float ex){
    if (base == 0)
        return 0;
    // power of 0
    if (ex == 0){
        return 1;
    // negative exponenet
    }else if( ex < 0){
        return 1 / pow(base, -ex);
    // fractional exponent
    }else if (ex > 0 && ex < 1){
        return nth_root(base, 1/ex);
    }else if ((int)ex % 2 == 0){
        float half_pow = pow(base, ex/2);
        return half_pow * half_pow;
    //integer exponenet
    }else{
        return base * pow(base, ex - 1);
    }
}
int main_pow(int, char **){
    for (int ii = 0; ii< 10; ii++){\
        cout << "pow(" << ii << ", .5) = " << pow(ii, .5) << endl;
        cout << "pow(" << ii << ",  2) = " << pow(ii,  2) << endl;
        cout << "pow(" << ii << ",  3) = " << pow(ii,  3) << endl;
    }
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

测试:

pow(0, .5) = 0.03125
pow(0,  2) = 0
pow(0,  3) = 0
pow(1, .5) = 1
pow(1,  2) = 1
pow(1,  3) = 1
pow(2, .5) = 1.41421
pow(2,  2) = 4
pow(2,  3) = 8
pow(3, .5) = 1.73205
pow(3,  2) = 9
pow(3,  3) = 27
pow(4, .5) = 2
pow(4,  2) = 16
pow(4,  3) = 64
pow(5, .5) = 2.23607
pow(5,  2) = 25
pow(5,  3) = 125
pow(6, .5) = 2.44949
pow(6,  2) = 36
pow(6,  3) = 216
pow(7, .5) = 2.64575
pow(7,  2) = 49
pow(7,  3) = 343
pow(8, .5) = 2.82843
pow(8,  2) = 64
pow(8,  3) = 512
pow(9, .5) = 3
pow(9,  2) = 81
pow(9,  3) = 729
Run Code Online (Sandbox Code Playgroud)