使用数组完成两个超长正整数的乘法_java大数算法完成五则运算之类基础

2a0a700619195797c6e85d403d0dc512.png

大家好,我是black,这是我专栏的第一篇文章,说点啥呢,专栏的目的就是分享和展示自己的思想和价值技术,我当然也不例外,这应该是我想要做这个专栏的最初的冲动原因吧。

回到正题,之所以会做用算法做大数的四则运算是因为在参加蓝桥杯比赛的时候被两道大数题给坑惨了,因为训练的时候没做过大数的题,在这上面吃了大亏,回来后痛定思痛,在网上找了一些方法,才发现有BigDecimal和BigInteger这两个api类可以完美解决我的问题,我自然很好奇,于是在网上找到了这两个类的源码来看,结果越看越头痛,整个源码没法在我心中有一个完整的结构,后来突然内心一动,为什么不自己来写一个类似的api类呢?这个想法出来后就在心里一发不可收拾,越加无法控制,说动就动。

类名:BigNum

功能:实现整数大数的五则运算,同时该类使用了Comparable接口,可以进行排序比较

属性:

  1. NUM:存放表示大数的数组
  2. SIGN:存放大数的正负号
  3. DIGITS:存放大数的位数
  4. 所有属性均为final,不可修改

构造方法:

  1. BigNum(String number);使用传入的字符串转换成int型数组,会过滤掉开头的零和非数字以及非正负号以外的其它所有符号,会忽略小数点及小数点后的所有字符,以最后一次出现的“-”“+”为该大数符号,如未指定则默认为“+”,如果字符串为null或空将会抛出异常
  2. BigNum(int[] numArr, char sign);过滤传入的int型数组的开头的零,传给NUM,如果数组中的数字超过一位将拆分为多位数,将sign传给SIGN,如果numArr为空,或者sign不为正负号将抛出异常

主要方法:

  1. add:加
  2. sub:减
  3. mul:乘
  4. div:除
  5. rem:取余
  6. 以及一些具体做运算的方法,将在讲到加减乘除这些方法时一并讲

其它方法:

  1. public static int[] stringToIntArr(String s);将传入的字符串转换成int数组,该方法为静态方法,会过滤掉开头的零和非数字,会忽略小数点及小数点后的所有字符。
  2. public static String intArrToString(int arr[]);将传入的int数组转换成字符串,该方法为静态方法。
  3. public int compareTo(BigNum num);比较两个bignum对象的大小,包括符号,若当前对象小于,等于,大于num,则返回负整数,零,正整数
  4. private int ArrCompare(int a[], int b[]);大数数组同位数下比较大小,无符号,若a小于,等于,大于b,则返回负整数,零,正整数
  5. private int intArrCompaerTo(int numA[], int numB[]);判断两个大数数组的大小,无符号,若numA小于,等于,大于numB,则返回负整数,零,正整数
  6. public String toString();重写toString,将NUM数组转换成字符串,同时在前面加上符号,正号默认不加。

贴上代码:

public class BigNum implements Comparable<BigNum> {

    /**
     * 表示大数的数组
     */
    public final int NUM[];
    /**
     * 表示大数的正负号
     */
    public final char SIGN;
    /**
     * 表示大数的位数
     */
    public final int DIGITS;

    public BigNum(String number) throws Exception {
        if (number == null || number =="") {
            throw new Exception("字符串为空!");
        }
        char numChar[] = number.toCharArray();
        char sign = 0;
        //从左往右获取输入的值
        for (int i = 0; i < numChar.length; i++) {
            //设置大数正负号,以最后一个符号为准
            if (numChar[i] == 43 || numChar[i] == 45) {
                sign = numChar[i];
            }
        }
        if (sign == 0) {
            sign = '+';
        }
        NUM = stringToIntArr(number);
        SIGN = sign;
        DIGITS = NUM.length;
    }

    public BigNum(int[] numArr, char sign) throws Exception {
        if (numArr == null) {
            throw new Exception("数组为空!");
        }
        if (sign != '-' && sign != '+') {
            throw new Exception("符号错误!非正负号!");
        }
        SIGN = sign;
        NUM = stringToIntArr(intArrToString(numArr));
        DIGITS = NUM.length;
    }
    public static int[] stringToIntArr(String s) {
        char numChar[] = s.toCharArray();
        StringBuilder sb = new StringBuilder();
        boolean flag = true;
        for (int i = 0; i < numChar.length; i++) {//从左往右获取输入的值
            if (numChar[i] == 48 && flag) {//过滤掉开头的零
                continue;
            }
            if (numChar[i] == 46) {//忽略小数点'.'后的值
                break;
            }
            if (numChar[i] > 47 && numChar[i] < 58) {//过滤掉非数字
                flag = false;
                sb.append(numChar[i]);
            }
        }

        if (flag) {
            sb.append("0");
        }
        char tempCharArr[] = sb.toString().toCharArray();
        int num[] = new int[tempCharArr.length];
        for (int j = 0; j < num.length; j++) {//将获取到的数字从char转换成int
            num[j] = Integer.valueOf("" + tempCharArr[j]);
        }
        return num;
    }

    public static String intArrToString(int arr[]) {
        StringBuilder sb = new StringBuilder(arr.length);
        boolean flag = true;
        for (int i : arr) {
            if (i == 0 && flag) {//过滤掉开头的零
                continue;
            }
            flag = false;
            sb.append(i);
        }
        if (flag) {
            sb.append("0");
        }
        return sb.toString();
    }

    /**
     * 比较两个bignum对象的大小,包括符号。
     * 若当前对象小于,等于,大于比较对象,则返回负整数,零,正整数
     *
     * @param num
     * @return
     */
    @Override
    public int compareTo(BigNum num) {
        if (this == num) {
            return 0;
        }
        if (num == null) {
            return 1;
        }
        if (SIGN < num.SIGN) {//当前对象正号      +号的ascll为43,-号为45  
            return 1;
        } else if (SIGN > num.SIGN) {//当前对象负号
            return -1;
        } else {//同号
            if (SIGN == '+') {//同正
                if (DIGITS > num.DIGITS) {//位数大
                    return 1;
                } else if (DIGITS < num.DIGITS) {//位数小
                    return -1;
                } else {//位数相同
                    return ArrCompare(NUM, num.NUM);
                }
            } else {//同负,结果全部取反
                if (DIGITS > num.DIGITS) {//位数大
                    return -1;
                } else if (DIGITS < num.DIGITS) {//位数小
                    return 1;
                } else {//位数相同
                    return -1 * ArrCompare(NUM, num.NUM);
                }
            }
        }
    }

    /**
     * 大数数组同位数下比较大小,无符号。
     * 若a小于,等于,大于b,则返回负整数,零,正整数
     *
     * @param a
     * @param b
     * @return
     */
    private int ArrCompare(int a[], int b[]) {
        for (int i = 0; i < b.length; i++) {
            if (a[i] > b[i]) {
                return 1;
            } else if (a[i] < b[i]) {
                return -1;
            }
        }
        return 0;
    }

    /**
     * 判断两个大数数组的大小,无符号。
     * 若当前数组小于,等于,大于比较数组,则返回负整数,零,正整数
     *
     * @param numArr
     * @return
     */
    private int intArrCompaerTo(int numA[], int numB[]) {
        if (numA == numB) {
            return 0;
        }
        if (numA.length > numB.length) {
            return 1;
        } else if (numA.length < numB.length) {
            return -1;
        } else {
            return ArrCompare(numA, numB);
        }
    }

    @Override
    public String toString() {
        return (SIGN == '+' ? "" : SIGN) + intArrToString(NUM);//忽略正号
    }

最后,为了避免太长,我将会写成一个系列~~请关注本专栏后续的大数运算系列,接下来将会对五则运算逐个详解(其实是为了多两篇文章。。。)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值