在浮点中实现pow()函数的最有效方法

时间:2010-04-18 23:39:18

标签: c++ c floating-point math

我正在尝试实现自己的pow()和sqrt()函数版本,因为我的自定义库没有pow()/ sqrt()浮点支持。

有人可以帮忙吗?

7 个答案:

答案 0 :(得分:9)

是的,Sun可以(我现在认为是甲骨文):

fdlibm,“可自由分发的数学库”,有sqrtpow,以及许多其他数学函数。

但是,它们是相当高科技的实现,当然,没有什么是这样的“最有效”的实现。您是否使用源代码完成任务,或者您真的没有那么多寻找powsqrt,但实际上是在寻找浮点算法编程方面的教育?

答案 1 :(得分:8)

当然 - 如果你有指数和自然的日志功能,这很容易。

y = x^n开始,您可以获取双方的自然日志:

ln(y) = n*ln(x)

然后取双方的指数为你提供你想要的东西:

y = exp(n*ln(x))

如果你想要更好的东西,我认识的最好的地方是Abramowitz and Stegun

答案 2 :(得分:3)

请注意,如果您的指令集有平方根或功率指令,那么使用它会更好。例如,x87浮点指令具有指令fsqrt,并且SSE2添加包括另一指令sqrtsd,这可能比用C编写的大多数解决方案快得多。事实上,至少当在x86机器上进行编译时,gcc使用这两个指令。

然而,对于权力来说,事情变得有点模糊。 x87浮点指令集中有一条指令,可用于计算n * log2(n),即fyl2x。另一条指令fldl2e将log2(e)存储在浮点堆栈中。你可能想看看这些。

您可能还想了解各个C库如何执行此操作。例如,dietlibc只使用fsqrt

sqrt:
    fldl 4(%esp)
    fsqrt
    ret

glibc将Sun的实现用于硬件平方根指令不可用的机器(在sysdeps/ieee754/flt-32/e-sqrtf.c下),并在x86指令集上使用fsqrt(尽管可以指示gcc而是使用sqrtsd指令。)

答案 3 :(得分:2)

使用迭代牛顿方法正确实现平方根。

答案 4 :(得分:1)

double ipow(int base, int exp)
{

bool flag=0;
if(exp<0) {flag=1;exp*=-1;}
int result = 1;
while (exp)
{
    if (exp & 1)
        result *= base;
    exp >>= 1;
    base *= base;
}
if(flag==0)
return result;
else
return (1.0/result);
}
//most suitable way to implement power function for integer to power integer

答案 5 :(得分:0)

为计算C中浮点数的平方根,如果你定位x86,我建议使用fsqrt。 您可以使用以下ASM指令:

asm("fsqrt" : "+t"(myfloat));

对于GCC或

asm {

fstp myfloat

fsqrt

fldp myfloat

}

或类似Visual Studio的东西。

为了实现pow,使用像upitasoft.com/link/powLUT.h那样的大开关语句应该这样做。 它可能会导致一些缓存问题,但是如果你保持它不应该是一个问题,只需限制范围(注意,你仍然可以优化我提供的代码)。

如果你想支持浮点数,那就更难了...... 您可以尝试使用自然对数和指数函数,例如:

float result = exp(number * log(power));

但通常它很慢和/或不精确。

希望我帮助过。

答案 6 :(得分:-2)

我能想到做pow()的最快方法就是沿着这些方向发展(注意,这很复杂):


//raise x^y
double pow(double x, int y) {
    int power;
    map<int, double> powers;
    for (power = 1; power < y; power *= 2, x *= x)
        powers.insert(power, x);

    while (power > y) {
        //figure out how to get there
        map<int, double>::iterator p = powers.lower_bound(power - y);
        //p is an iterator that points to the biggest power we have that doesn't go over power - y
        power -= p->first;
        x /= p->second;
    }

    return x;
}

我不知道如何实现十进制功率。我最好的猜测是使用对数。

编辑:我正在尝试对数解决方案(基于y),而不是您提出的线性解决方案。让我解决这个问题并进行编辑,因为我知道它有效。

编辑2:呵呵,我的坏人。 power * = 2而不是power ++