我正在尝试实现自己的pow()和sqrt()函数版本,因为我的自定义库没有pow()/ sqrt()浮点支持。
有人可以帮忙吗?
答案 0 :(得分:9)
是的,Sun可以(我现在认为是甲骨文):
fdlibm,“可自由分发的数学库”,有sqrt和pow,以及许多其他数学函数。
但是,它们是相当高科技的实现,当然,没有什么是这样的“最有效”的实现。您是否使用源代码完成任务,或者您真的没有那么多寻找pow
和sqrt
,但实际上是在寻找浮点算法编程方面的教育?
答案 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使用这两个指令。
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 ++