0.简介
前面实现了log2,我就顺势用这个函数来构造求a^x的结果。
1.方法推导
我们通过关系式子的变换可以得到等式
,这样一来我们只需要针对2的n次幂来求解。将2^x泰勒展开
,ln2我们可以预先求出。
对于幂大于1的情况,例如
,变换成
,因为
比较容易计算,
利用泰勒展开式计算,这里要处理一下幂是负数的时候,然后将所有小数的幂次都直接带入泰勒展开式,大于1的部分直接计算就可以。
2.实现
#include<iostream>
#include<ctime>
using namespace std;
#define LN2 0.69314718055994530941723212145818
typedef double ldouble;
double baselog2(double n)
{
n-=1;
double x = -1,result = 0;
for (int i = 1; i < 30; i++)
result += ((x = x * n * -1) / i);
return result/LN2;
}
double mylog2(double n)
{
double result = 0;
if (n >= 0.5 && n <= 1)
result = baselog2(n);
else if (n >= 0.1 && n < 0.5)
{
while(n<=1)
{
n *= 2;
--result;
}
result += (baselog2(n/2) + 1);
}
else if (n > 0 && n < 0.1)
{
while (n<0.1)
{
n *= 10;
result += (-0.32192809488736229 - 3);//这里预计算了log2(0.3)-3
}
result += (mylog2(n));
}
else if (n > 1)
{
while (1 <= n)
{
//bitnum*= 2;//实际就是每次除以2,让n小于1
n /= 2;
++result;
}
result += (mylog2(n));
}
return result;
}
double myln(double n)
{
return mylog2(n) / 1.4426950408889634;
}
double _2x(double n)
{
double result = 1, x = 1;
for (int i = 1; i < 20; i++)
{
result += (x = (n * x * LN2) / i);
}
return result;
}
double mypow(double a, double x)
{
if (x == 0)
return 1;
if (a == 0)
return 0;
double t = x * mylog2(a),result = 1;
int integer = 0;
double eps = 0;
if (abs(t) >= 1)//取整数
integer = t;
if (t > 0)
{
while (integer > 0)
{
result *= 2;
integer--;
}
eps = t - (int)t;
}
else if (t < 0)
{
while (integer < 0)
{
result /= 2;
integer++;
}
eps = (int)fabs(t)-fabs(t);
}
else
return 1.0;
return result * _2x(eps);
}
int main()
{
double n = 0.011111555;
float a, b;
a = mypow(n,0);
b = pow(n, 0);
cout << a << endl;
cout << b << endl;
return 0;
}
3.问题
由于计算过程中,LN2等一些预计算的值是不精确数值,反复自乘会不断放大误差,所以在double下和系统的pow有一点点误差,不过也在可以接受范围内,在float下问题不大。
版权声明:本文为ARTELE原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。