a的n次方的快速算法

en二进制幂

 对于an次幂求解这个问题,不少人看到后都觉得没有什么内容吧!我第一次想到这个问题也觉得没有什么内容,但是后来仔细想想,里面还真是有学问哦!

  想想看如果我们求 a8  ,有以下两种方法

  1a8  = a * a * a * a * a * a * a * a 需要计算 7次乘法

  2a 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<Integer> s ;

 

 

    public AN(int a, int bin) {

        this.a = a;

        this.bin = bin;

        s = new Stack<Integer>();

        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<Integer> 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<Integer> s = new Stack<Integer>();

        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<Integer> s = new Stack<Integer>();

           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是整数的话计算时间过短,那么算法的速度就体现不出来了。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值