Mathematics & Programme

返回主页<-

高精度求乘幂

先从简单一些的整数乘幂开始, 因为实数乘幂的计算可归结为正整数次方, 开正整数次方和求倒数. 见 指数&对数

指数是整数的情况
先看一个例子:

计算 216 .我们可以通过代数式的变形来减少计算步骤:

  216 = 48 = 164 = 2562 = 65536

类似地计算 220.

  220 = 410 = 165 = 164*16 = 2562*16 = 65536*16 = 1048576

可见, 我们把问题转化为多次求两大数的积. 如果求积时仍用经典乘法, 并不能使计算时间显著减少, 因为时间复杂度仍是O(n2). 由于我们有快速乘法, 使得这么做可以使乘幂计算快许多:

////求 xy ////

result=x;

While y mod 2=0 

{

y=y div 2;

result=result*result;

}

tmp=1;

While y<>1

{

If y mod 2<>0 then { tmp=tmp*result; y=y-1;};

While y mod 2=0

{

y=y div 2;

result=result*result;

}

}

 

result=result*tmp

result就是所求结果.

 对以上代码进行优化:

 

////求 xy ////

tmp=x;

result=1;

While y<>1

{

While (y and 1)<>1

{

y=y shr 1;

tmp=tmp*tmp;

}

result=result*tmp;

y=y-1;

}

 

result=tmp*result;

还有一种基于二进制的乘方算法, 例:

a15=a2^3+2^2+2+1=(((a2)·a)2·a)2·a

由以上,设 e=(en-1,en-2,...,e1,e0) 为指数的二进制表示;

1. p←ae(n-1); i←n-2;

2. p=p2;

3. 若 ei=1,p=pa;

4. i--; 若 i>=0 转到2;

5. 输出 p.

 

实数乘幂的计算

     正如开头所说的"可归结为正整数次方, 开正整数次方和求倒数". 但是对于类似

 14^(100000000π) 的大实数乘幂就无能为力了.

关于这个问题站长也没什么好办法.只好按下列步骤处理 x^y:

将指数y分为整数a, 小数部分b .

x^y=x^(a+b)=x^a*x^b

按整数指数乘幂计算 x^a.

利用 x^b=e^(b*ln(x)) 计算第二部分.

两部分相乘得 x^y.

其中计算又要涉及到乘幂 e^() 的计算, 似乎又回到开头的问题.

不过, 幸好有 ey=1+y+y2/2!+y3/3!+...+yn/n!+... 同样可把把 y 分为整数,小数部分,整数部分同样是按整数指数乘幂计算( e 的值预先用 e^1 求出), 小数部分按上式算.

ex=1+x+x2/2!+x3/3!+...+xn/n!+...

 

直接计算(一项一项地算)的时间复杂度容易求得是O(n2), 但这已经几乎是计算它的最好的式子了. 

算之前可以利用 ex=(ex/2)2 递归地把指数化到适当小. 再代入幂级数.

没有经过实践的:

 

 对于 e1/x=1+1/x+1/(x22!)+1/(x33!)+...+1/(xnn!)+...

 

设: Q(a,b)=(a+1)(a+2)...(b-1)bxb-a

P(a,b)=Q(a+1,b)+Q(a+2,b)+...Q(b-1,b)+1

 

则:  

n

e1/x =

1 =1+ P(0,n)


k!xk Q(0,n)
k=0

有初值

P(c,c+1)=1,        Q(c,c+1)=(c+1)x, 

P(c,c+2)=(c+2)x+1, Q(c,c+2)=(c+1)(c+2)x2 .

递推关系

m=

[(a+b)/2]  也可以取任意 0<k<1 计算 m=[k(a+b)] 

P(a,b)=

P(a,m)Q(m,b)+P(m,b)

Q(a,b)=

Q(a,m)Q(m,b)

 

 

 Last update 10/2/2004

交流:  留言本 or xyy82148@163.com