计算机与代数---如何计算pow---方法和实现

0.简介

前面实现了log2,我就顺势用这个函数来构造求a^x的结果。

1.方法推导

我们通过关系式子的变换可以得到等式\small a^{x}=2^{^{xlog_{2}(a)}},这样一来我们只需要针对2的n次幂来求解。将2^x泰勒展开\small 1+ln(2)x+\frac{ln2^{2}*x^{2}}{2!}+\frac{ln2^{3}*x^{3}}{3!}....,ln2我们可以预先求出。

对于幂大于1的情况,例如\small 2^{4.5},变换成\small 2^{4}*2^{_{0.5}},因为\small 2^{4}比较容易计算,\small 2^{0.5}利用泰勒展开式计算,这里要处理一下幂是负数的时候,然后将所有小数的幂次都直接带入泰勒展开式,大于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下问题不大。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值