java求大数幂算法

1.适用范围:幂的底数为long数,指数为int数,如13^3,65536^4,1048576^64,1073741824^256

2.思路:

2.1.大数转为01串的byte数组->13=1101

2.2.乘法的本质加法->2*3=2+2+2

2.3.乘法的一个因子转为基于2的多项式结构,将计算复杂度从指数级降为对数级->3*5=3*(2^0+2^2)

3.性能分析:与BigInteger性能相比,20+大整数,8+幂数相差30ms(i5-5200+16G+64bit环境)

    /** 
     * 描述:getBit 返回实际的01串
     * @param a
     * @return
     * @CreateOn 2023年3月12日  上午11:18:06
     * @author chun_chang
     */
    public static byte[] getBit(long a) {
        String bs = Long.toBinaryString(a);
        int l = bs.length();
        byte[] b = new byte[l];

        for (int i = l - 1; i >= 0; i--) {
            b[i] = bs.charAt(i) == '1' ? (byte) 1 : (byte) 0;
        }
        return b;
    }

    
    /** 
     * 描述:add 01数加法
     * @param a 0,1
     * @param b 0,1
     * @param o 前一步加法是否产生进位
     * @return 返回01串
     * @CreateOn 2023年3月12日  上午10:04:51
     * @author chun_chang
     */
    public static byte[] add(byte a, byte b, boolean o) {
        byte[] c = new byte[2];
        if (a == (byte) 1 && b == (byte) 1) {
            c[0] = (byte) 1;
            c[1] = o ? (byte) 1 : (byte) 0;
            return c;
        }
        if (a == (byte) 0 && b == (byte) 0) {
            c[0] = (byte) 0;
            c[1] = o ? (byte) 1 : (byte) 0;
            return c;
        }
        if (o) {// 01,10
            c[0] = (byte) 1;
            c[1] = (byte) 0;
        } else {
            c[1] = (byte) 1;
        }
        return c;
    }
    /** 
     * 描述:add 两个01数组相加
     * @param a 01数组
     * @param b 01数组
     * @return 返回01串
     * @CreateOn 2023年3月12日  上午10:59:10
     * @author chun_chang
     */
    public static byte[] add(byte[] a, byte[] b) {
        /* 1.交换数组,确保a的长度大于b */
        int l1 = a.length;
        int l2 = b.length;
        if (l1 < l2) {// 让a为长数组,b为短数组
            byte[] c = new byte[l1];
            System.arraycopy(a, 0, c, 0, a.length);
            a = b;
            b = c;
            l1 = a.length;
            l2 = b.length;
        }
        
        int j = l1 - l2;
        byte[] c = new byte[l1 + 1];//返回值
        boolean o = false;
        int i = c.length - 1 - j;
        while (i > 0) {//运算次数
            byte[] t = add(a[j + i - 1], b[i - 1], o);
            c[i + j] = (byte) t[1];
            o = t[0] == (byte) 1;
            i--;
            if (i == 0 && o) {
                c[i + j] = (byte) 1;
            }
        }
        
        if (j != 0) {
            if(c[j] == (byte) 1) {// 未参与计算部分产生了进位
                byte[] g = new byte[j];
                System.arraycopy(a, 0, g, 0, g.length);
                o = true;
                i = g.length - 1;
                while (o) {
                    byte[] t = add(i == -1 ? (byte) 0 : g[i], (byte) 1, false);//g已经计算完成时,仍需要进位
                    o = t[0] == (byte) 1;
                    if (o) {
                        c[j] = (byte) 0;
                    } else {
                        c[j] = (byte) 1;
                        if(i > 0) {
                            System.arraycopy(g, 0, c, 1, i);
                        }
                    }
                    j--;
                    i--;
                }
            } else {
                System.arraycopy(a, 0, c, 1, j);
            }
        }
        
        if (c[0] == (byte) 0) {//未产生进位,回退至原始数据长度
            byte[] r = new byte[c.length - 1];
            System.arraycopy(c, 1, r, 0, r.length);
            c = r;
        }
        return c;
    }
    
    /** 
     * 描述:pow 若计算8字节以上的幂数,需使用BigInteger
     * @param a 底数
     * @param e 指数
     * @return
     * @CreateOn 2023年3月12日  上午9:42:19
     * @author chun_chang
     */
    public static byte[] pow(long a, int e) {
        byte[] b0 = getBit(a);
        byte[] t = b0;// 临时变量---每次左移一位结果
        byte[] t0 = b0;// 临时变量---一次幂乘结果---2^0+2^1+...+2^n=a
        byte[] t1 = {};// 临时变量---每次迭代相加结果
        int i = e;
        while (i > 1) {
            if (b0[b0.length - 1] == (byte) 1) {
                t1 = add(t0, t1);
            }
            for (int j = 1; j < b0.length; j++) {// 计算a的2^n次方次相加结果
                t = append(t, (byte) 0);// 每次乘2即相当于左移一位
                if (b0[b0.length - 1 - j] == (byte) 1) {
                    t1 = add(t1, t);
                }
            }
            t = t1;
            t0 = t1;
            t1 = new byte[]{ (byte) 0 };
            i--;
        }
        t0 = convertByteArr(t0);//处理t1数组(01数)为真实byte[]
        return t0;
    }
    
    /* 99.工具类 ********************************************/
    public static byte[] append(byte[] a, byte b) {
        if (a == null) {
            return new byte[] { b };
        }

        int l = a.length;
        byte[] r = new byte[l + 1];
        System.arraycopy(a, 0, r, 0, l);
        r[l] = b;
        return r;
    }
    
    /** 
     * 描述:convertByteArr 01串数组转为真实byte[]
     * @param a
     * @return
     * @CreateOn 2023年3月18日  上午9:05:39
     * @author chun_chang
     */
    public static byte[] convertByteArr(byte[] r) {
        int l = r.length / 8 + (r.length % 8 == 0 ? 0 : 1);
        byte[] r0 = new byte[l];//最后结果的真实bit位,多一字节,防止出现负数
        byte[] r1 = new byte[l * 8];//扩展r为8的倍数
        
        if(r.length % 8 == 0) {
            r1 = r;
        } else {
            System.arraycopy(r, 0, r1, r1.length - r.length, r.length);
        }
        
        int i = 0;
        while (i < r1.length / 8) {// 1111101
            int k1 = 1;
            byte t0 = (byte) 0;
            for (int j = 7; j >= 0; j--) {
                t0 += r1[8 * i + j] == (byte) 0 ? (byte) 0 : (byte) k1;
                k1 *= 2;
            }
            r0[i] = t0;
            i++;
        }
        byte[] r2 = new byte[r0.length + 1];
        System.arraycopy(r0, 0, r2, 1, r0.length);
        return r2;
    }
    
    
    
    public static void printByte(byte[] a) {
        for (int i = 0; i < a.length; i++) {
            byte b = a[i];
            switch (b) {
                case (byte) 1: System.out.print("1"); break;
                case (byte) 0: System.out.print("0"); break;
                default: break;
            }
            if (i != 0 && (a.length - i - 1) % 4 == 0 && i != a.length - 1) {
                System.out.print("-");
            }
        }
        System.out.println();
    }

    public static void main(String[] args) {
        try {
            long s = System.currentTimeMillis();
            long a = 65536;// 65536---1048576---536870912---1073741824
            int e = 256;
            byte[] t1 = pow(a, e);
            BigInteger bi  = new BigInteger(t1);
            System.out.println(String.format("耗时:%sms,%s^%s = %s", (System.currentTimeMillis() - s), a, e, bi));
            
            long s1 = System.currentTimeMillis();
            BigInteger b1  = BigInteger.valueOf(a);
            BigInteger b2  = b1.pow(e);
            System.out.println(String.format("耗时:%sms,%s^%s = %s", (System.currentTimeMillis() - s1), a, e, b2));
            
            
            
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

耗时:27ms,536870912^256 = 702567101168536800922438590478865377668017001719915936579448912372598510715744763501882384612611566959117382494034312459455139914468038639460450383968644187276540204267413191969851320248492054104829090392640235960372015528898953417931025961211318901284945592338652387148889380139477673159673166984480858462104241873595434916008973279232690529636443623781982429995789170528351897122958739299052588215875549040296539813258471962309855251445352165360083482705227628564019875799210353202107711165274645247422723960748358673075052124925743656271067433352584177595131955952228868008409462423993636901021191146005210485725746249697492833141029213005140068829544325079486203500595980681399888021767822418563636109620918528346475469919357732436856244774953025784520910440245715254877697294968137714784970423847899034933148707338363052237617887197809531083256573604655618285407846288242153322994102834454883804418346444387462456790915102195175112593267832744876992469909478389663089430284854465913193931668535566593259529740689983148992706222437314956585372122129300992709406835892917374132958196105937002075215338312971490288354904725455748883750521542061490602682986125493092600841256535661692898466404805288388366665776276054099173372626748739933959132329871224658351267277850226392896225632861028885048664859392189984074814039827506368730257825656963203130339656565366099380135540718477596064143922571054209027700332797453309531061808314919329526622785778002738118608964351032592464408805847153207590853628353829683860223642868588852146970087883145237207403702297871836567968045497844960690660791494499997942130835795684443402861731108217771212163176237553923239702728600972947986460321978156507413727675962636506415822081344795767176509895667069969784352272563970900203401353241744099434703372080560349033093647680927506283666689457225189459896651540255824273932131306103174535680085257809209287122497227607986097049809908690596914837170777097789610579137508463360958989558526445443233014342065768862001587066902201545763318304941507767877856847648343871533710666108369002436748447879531979060305657642555847652329531745882539086858722020041727380861290865588040797570576462622422904384833884254746498287728246533422882094709638340559241216
耗时:0ms,536870912^256 = 702567101168536800922438590478865377668017001719915936579448912372598510715744763501882384612611566959117382494034312459455139914468038639460450383968644187276540204267413191969851320248492054104829090392640235960372015528898953417931025961211318901284945592338652387148889380139477673159673166984480858462104241873595434916008973279232690529636443623781982429995789170528351897122958739299052588215875549040296539813258471962309855251445352165360083482705227628564019875799210353202107711165274645247422723960748358673075052124925743656271067433352584177595131955952228868008409462423993636901021191146005210485725746249697492833141029213005140068829544325079486203500595980681399888021767822418563636109620918528346475469919357732436856244774953025784520910440245715254877697294968137714784970423847899034933148707338363052237617887197809531083256573604655618285407846288242153322994102834454883804418346444387462456790915102195175112593267832744876992469909478389663089430284854465913193931668535566593259529740689983148992706222437314956585372122129300992709406835892917374132958196105937002075215338312971490288354904725455748883750521542061490602682986125493092600841256535661692898466404805288388366665776276054099173372626748739933959132329871224658351267277850226392896225632861028885048664859392189984074814039827506368730257825656963203130339656565366099380135540718477596064143922571054209027700332797453309531061808314919329526622785778002738118608964351032592464408805847153207590853628353829683860223642868588852146970087883145237207403702297871836567968045497844960690660791494499997942130835795684443402861731108217771212163176237553923239702728600972947986460321978156507413727675962636506415822081344795767176509895667069969784352272563970900203401353241744099434703372080560349033093647680927506283666689457225189459896651540255824273932131306103174535680085257809209287122497227607986097049809908690596914837170777097789610579137508463360958989558526445443233014342065768862001587066902201545763318304941507767877856847648343871533710666108369002436748447879531979060305657642555847652329531745882539086858722020041727380861290865588040797570576462622422904384833884254746498287728246533422882094709638340559241216

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值