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

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

有人可以帮忙吗?

是的,Sun可以(我现在认为是Oracle):

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

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

当然 – 如果你有指数和自然的日志function,这很容易。

由于y = x^n ,您可以采用双方的自然对数:

 ln(y) = n*ln(x) 

然后采取双方的指数为您提供您想要的:

 y = exp(n*ln(x)) 

如果你想要更好的东西,我所知道的最好的地方是Abramowitz和Stegun 。

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

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

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

 sqrt: fldl 4(%esp) fsqrt ret 

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

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

 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 

为了计算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)); 

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

希望我帮忙。

我可以想到做一个pow()的最快方法是沿着这些方向(注意,这很复杂):

 //raise x^y double pow(double x, int y) { int power; map powers; for (power = 1; power < y; power *= 2, x *= x) powers.insert(power, x); while (power > y) { //figure out how to get there map::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:呵呵,我的坏。 功率* = 2而不是功率++