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;
}