快速幂

x的n次方:x^n,

将n用二进制表示:假设n=13,则n的二进制为1101,则n=1*2^0+0*2^1+1*2^2+1*2^3=2^0+2^2+2^3,

所以:x^n=x^(2^0+2^2+2^3)=x^(2^0) * x^(2^2) * x^(2^3),

x^(2^i)=(...((x^2)^2)...)^2,一共有i次求平方,易得:x^(2^(i+1))=(x^(2^i))^2,设T(x,i)=x^(2^i),则有:T(x,i+1)=(T(x,i))^2,上一行的式子可表示为:x^n=T(x,0) * T(x,2) * T(x,3),

有高中数学基础不难发现:2^i+2^(i+1)+2^(i+2)+...+2^j=2^(j+1) - 2^i,即:T(x,i) * T(x,i+1) * T(x,i+2) ... * T(x,j) = T(x,j+1) / T(x,i),

所以,假设n的二进制为1110001100,则:x^n=T(x,2) * T(x,3) * T(x,7) * T(x,8) * T(x,9) = T(x,4) / T( x,2) * T(x,10) / T(x,7),

那么,对于上面一行的n,求x^n,设ans为计算结果变量,先将ans初始化为1,:ans=1。设S=x。

我们从n的二进制的最低位开始,设S=S^2=x^2=T(x,1),往高位每进一位,若未遇到1,则令S=S^2,即再从左往右第i位,S=x^(2^i)=T(x,i),当到达i=3时,数值为1,此时先不更新S,则此时S=x^(2^2)=T(x,2),先将ans/=S,即ans/=T( x,2),再将S=S^2=x^(2^3)=T(x,3)。

之后若未遇到0,则每向高位进一位,将S=S^2=x^(2^i)=T(x,i),直到我们遇到从左往右第5位的0(i=5),此时先不更新S,则此时S=x^(2^4)=T(x,4),先将ans*=S,即:ans*=T(x,4),再将S=S^2=x^(2^5)=T(x,5)。

接下来以此类推,总结一下规律就是:设i为当前位,每向高位前进一位(向左),若该位数值与前一位相同,则直接更新S,令S=S^2=x^(2^i)=T(x,i),不用更新ans。

若该位数值与前一位不同,则分两种情况:

A.如果前一位为0,该一位为1,则此时先不更新S,则此时S=x^(2^(i-1))=T(x,i-1),先将ans/=S,即ans/=T( x,i-1),再将S=S^2=x^(2^i)=T(x,i)。

B.如果前一位为1,该一位为0,则此时先不更新S,则此时S=x^(2^(i-1))=T(x,i-1),先将ans*=S,即ans*=T( x,i-1),再将S=S^2=x^(2^i)=T(x,i)。

即:只在进入1数值段,和离开1数值段时,先更新ans,再更新S。否则直接更新S。

当然,若最低位为1,则在最低位右一位假想一个0,则在最低位时,是A的情况,则需先将ans/=S,此时ans=1/x。接下来的步骤就是上面说的。


//cpp

#include <iostream>
using namespace std;
const double pow2(double x,int n);

int main()
{
	cout << pow2(-2,-pow2(2,2)+1) << endl;
	while(cin.get()!='\n');
	return 0;
}

const double pow2(double x,int n)
{
	double ans=1;
	if(n<0)	//x^(-n) = (1/x)^(n)
	{
		x=1/x;
		n=-n;
	}
	if(n&1)	//n的二进制最低位为1时
		ans/=x;
	while(n)
	{
		if(n&1)	//进入1数值段
		{
			while(n&1)	//在1数值段上,更新x。当数值由1变成0时,跳出此while循环代码段。
			{
				x*=x;
				n>>=1;
			}
			ans*=x;	//前一位为1,该位为0,情况B,更新ans,但更新x的步骤交给另一个while
		}
		else  //进入0数值段
		{
			while(!(n&1))	//在0数值段上,更新x。当数值由0变成1时,跳出此while循环代码段。
			{
				x*=x;
				n>>=1;
			}
			ans/=x;	//前一位为0,该位为1,情况A,更新ans,但更新x的步骤交给另一个while
		}	//else
	}	//while
	return ans;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值