我正在阅读How can I write a power function myself?并且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;
}
}
虽然我不确定我是否正确翻译,因为所有给出.5作为指数的调用返回0.在答案中它声明它可能需要基于a^b = 2^(b * log2(a))
的log2(x),但是我不确定是否会把它放进去,因为我不确定该放在哪里,或者我是否正在考虑这一点。
注意:我知道这可能是在数学库中定义的,但我不需要为一些函数添加整个数学库的所有费用。
编辑:有没有人知道分数指数的浮点实现? (我已经看过一个双重实现,但那是使用寄存器的技巧,我需要浮点数,并添加一个库只是为了做一个技巧我会更好,只包括数学库)答案 0 :(得分:15)
以下是powf实际实现的链接。
我希望更简单的解决方案在结果中缺乏准确性或不处理InF和NaN参数。
http://opensource.apple.com/source/Libm/Libm-2026/Source/Intel/expf_logf_powf.c
http://opensource.apple.com/source/Libm/Libm-315/Source/ARM/powf.c
答案 1 :(得分:7)
我查看了本文here,其中描述了如何近似指数函数以获得双精度。在对维基百科进行了一些关于单精度浮点表示的研究后,我得出了等效的算法。他们只实现了exp函数,所以我找到了日志的反函数,然后只做了
POW(a, b) = EXP(LOG(a) * b).
编译这个gcc4.6.2产生的pow函数几乎比标准库的实现快4倍(用O2编译)。
注意:EXP的代码几乎是从我读过的论文中逐字复制的,LOG函数是从here复制的。
以下是相关代码:
#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);
}
你可以在这里做一些优化,或者也许这已经足够好了。 这是一个粗略的近似,但如果您对使用双重表示引入的错误感到满意,我想这将是令人满意的。
答案 2 :(得分:4)
我认为您可以尝试使用Taylor的系列来解决它, 检查一下。 http://en.wikipedia.org/wiki/Taylor_series
使用泰勒系列,您可以使用已知的结果(例如3 ^ 4)解决任何难以求解的计算,例如3 ^ 3.8。在这种情况下,你有 3 ^ 4 = 81所以
3 ^ 3.8 = 81 + 3.8 * 3(3.8 - 4)+ .. + ..等等取决于你的n有多大,你将得到更密切的问题解决方案。
答案 3 :(得分:3)
我认为您正在寻找的算法可能是'nth root'。初始猜测为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;
}
试验:
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
答案 4 :(得分:2)
我和我的朋友在使用OpenGL项目时遇到了类似的问题,而且在某些情况下math.h还不够。我们的教练也遇到了同样的问题,他告诉我们要分离整数和浮动部分的功率。例如,如果要计算x ^ 11.5,则可以计算sqrt(x ^ 115,10),这可能会得到更准确的结果。