a的n次方的快速算法

en二进制幂
对于a的n次幂求解这个问题,不少人看到后都觉得没有什么内容吧!我第一次想到这个问题也觉得没有什么内容,但是后来仔细想想,里面还真是有学问哦!
想想看如果我们求 a8 ,有以下两种方法
1. a8 = a * a * a * a * a * a * a * a 需要计算 7次乘法
2.a 8 = (a * a) * A * A (其中A = a * a) 需要计算3次乘法
对于这么简单的一个算法计算步骤差别的差别是很大的,那么对于一个通常的n怎么表示
普遍的求解方法呢?
经过多天的思考,始终没有结果,今天突然在一本书上看到有关这个求解的算法,心中大喜。把解决办法稍微整理一下,然后给出具体代码。




算法的思想
一般的对于 a (2x + b) = a2x * a b
所以就有
(b = 0时 ) : a 2x + b = (ax)2 ;
(b = 1时): a 2x + b = (a x)2 * a ;




对于 an ,先把 n的二进制表示写出,那么有
an = a (n1 n2 n3 n4 ..)(2) = …
那么我们从左到右就可以如下表(n = 13的时候 1101)
n的二进制位
1
1
0
1
累乘
a
a2 * a = a3
(a3)2 = a6
(a6)2 * a = a13




第一种代码:(用java实现,用了函数调用,效果比较失败)
package alg;




public class AN {
public static final int EXIT = 3;




int a; // 底数




int bin; // 指数




public Stack s ;




public AN(int a, int bin) {
this.a = a;
this.bin = bin;
s = new Stack();
s.push(EXIT);// 作为最后一个的标志
toBin(bin);
}

public void renew( int a,int bin){
this.a = a ;
this.bin = bin ;
s.push(EXIT);// 作为最后一个的标志
toBin(bin);
}
// 从左往右算
public int leftToRight() {
int i;
int result = 1;
while (true) {
i = s.pop();
switch (i) {
case 0:
result *= result;
break;
case 1:
result = result * result * a;
break;
case EXIT:
return result;
}
}
}




public int rightToLeft(int a) {
return 0;
}




/**
* 把十进制转成二进制 压入栈中
*
* @param ten
*/
public Stack toBin(int ten) {
int temp = ten;
int rest;
do {
rest = temp % 2;
temp = (temp - rest) / 2;
s.push(rest);
} while (temp != 0);
return s ;
}




public static void main(String[] args) {
AN a = new AN(3, 15);
Stack s = new Stack();
long start = System.currentTimeMillis();
for (int i = 0; i < 100000 ; i++) {
a.leftToRight();
a.renew(3,15);
}

System.out.println("use cq's method use time:"
+ (System.currentTimeMillis() - start));

int test = 1 ;
start = System.currentTimeMillis();
for(int i = 0 ; i < 100000 ; i++){
test = 1 ;
for(int j = 0 ; j < 15 ; j++){
test *= 3;
}
}
System.out.println("use nomarl method use time:"
+ (System.currentTimeMillis() - start));

}
}
运行结果:
use cq's method use time:62
use nomarl method use time:16
我的运算居然比基本的要慢!郁闷中!我决定改一下方法了!尽量减少函数调用!
改后的代码是
public class AN{
public static void main(String[]args){
double a = 2.123 ;
int bin = 31 ;

long start = System.currentTimeMillis();
for (int i = 0; i < 1000000 ; i++) {

Stack s = new Stack();
s.push(3);
int temp = bin ;
int rest;
do {
rest = temp % 2;
temp = (temp - rest) / 2;
s.push(rest);
} while (temp != 1);
s.pust(temp);
long high = 0;
double result = 1;
while (high != 3) {
high = s.pop();
switch ((int)high) {
case 0:
result *= result;
break;
case 1:
result = result * result * a;
break;
}
}
}

System.out.println("use cq's method use time:"
+ (System.currentTimeMillis() - start));

long test = 1 ;
start = System.currentTimeMillis();
for(long i = 0 ; i < 1000000 ; i++){
for(long j = 0 ; j < 31 ; j++){
test *= 2.123;
}
}
System.out.println("use nomarl method use time:"
+ (System.currentTimeMillis() - start));

}
}
运算结果:
use cq's method use time:453
use nomarl method use time:17265
对两种结果的分析:
Java的方法调用虽然相对其他语言来讲是做了优化的,但是仍然有一定开销,在做大量计算的时候仍然不能忽视。
第二中方法效果明显是因为a是一个小数,这样 a*a的计算时间就长了,如果 a是整数的话计算时间过短,那么算法的速度就体现不出来了。

相关文档
最新文档