java大數算法完成五則運算之除及取餘

這幾天偷懶去了~~今天把大數系列的最後一篇文章更新了~~


因爲商和餘其實是一個運算,只不過分屬兩個部分,所以放一起說了。


老樣子,先來講思路,原諒我水平有限,想不出來更好的方法,(有的話可以在下方評論告訴我~~)也沒遇見過類似的可以借鑑的算法,於是就用我們平時做除法的方法。


如上圖例子所示,商和餘都是未知的,而且都是需要多次在尾部添加數據,那麼數組棄用,集合又太龐大,但是我想到了用StringBuilder,數據可變,又方便添加數據,性能好,關鍵是還小,可以很方便的使用。


然後,我們需要一個循環來控制開始和結束,這個循環肯定是以被除數的最高位到最低位,那麼我們用a代表被除數,b代表除數,就有了這個for (int i = 0; i < a.length; i++)循環,每次循環我們要將對應的被除數位a[i]添加至餘數的末尾,然後將比較餘數與除數,這時我們會得到三個結果之中的一個。

  • 餘數小於除數:往商數的末尾加零,然後continue至下一次循環
  • 餘數等於除數:往商數的末尾加一,清零餘數,然後continue至下一次循環
  • 餘數大於除數:這也是我們着重要考慮的分支。

由於循環是一位一位往前推進的,所以餘數最多大除數一位,而一位的差距是不可能達到十倍的,最多商9。

例如除數101,被除數1000,餘數爲同樣位數時爲100,小於除數,進入下一循環,餘數爲1000,如果商10,除數與商的乘積 爲1010,大於1000,所以只能商9,餘89。

既然商只可能爲1至9,那我完全可以用一個1至9的循環來找出商。

最後把添加商,同時用餘數減去商與除數的乘積的差來當作新餘數,進入下一循環。

取餘也很簡單,最後留下的餘數即爲餘數。


最後上源代碼:代碼中所有調用到的函數請參考java大數算法完成五則運算之類基礎


public BigNum div(BigNum div) throws Exception {
        int newNum[] = null;//商數組
        char newNumSign = 0;//商正負號
        if (SIGN == div.SIGN) {//同號爲正,異號爲負
            newNumSign = '+';
        } else {
            newNumSign = '-';
        }
        if (DIGITS < div.DIGITS) {//被除數位數小於除數,結果直接爲零
            newNum = new int[1];
            newNum[0] = 0;
            newNumSign = '+';
        } else if (DIGITS == div.DIGITS) {//被除數位數等於除數
            switch (ArrCompare(NUM, div.NUM)) {//同位數下比較被除數與除數大小
                case -1://被除數小於除數
                    newNum = new int[1];
                    newNum[0] = 0;
                    newNumSign = '+';
                    break;
                case 0://被除數等於除數
                    newNum = new int[1];
                    newNum[0] = 1;
                    break;
                case 1://被除數大於除數
                    newNum = divAndRem(NUM, div.NUM, true);
                    break;
            }
        } else {//被除數位數大於除數
            newNum = divAndRem(NUM, div.NUM, true);
        }
        BigNum b = new BigNum(newNum, newNumSign);
        return b;
    }

    /**
     * 大數數組相除,a爲被除數,b爲除數,flag值爲true返回商數,false返回餘數     *
     * @param a
     * @param b
     * @param flag
     * @return
     */
    private int[] divAndRem(int a[], int b[], boolean flag) {
        StringBuilder quotient = new StringBuilder();//保存商數
        StringBuilder remainder = new StringBuilder();//保存餘數
        //根據平常進行除法運算的方法來實現
        for (int i = 0; i < a.length; i++) {//被除數從最高位到最低位循環
            remainder.append(a[i]);//添加餘數
            if ((i + 1) < b.length) {//如果餘數位數小於除數,則給對應商數位賦零,同時進入下一層循環
                quotient.append(0);
                continue;
            }
            //當餘數與除數位數一致或大於時判斷餘數與除數的大小
            switch (intArrCompaerTo(stringToIntArr(remainder.toString()), b)) {
                case -1://餘數小於除數,給對應商數位賦零,同時進入下一層循環
                    quotient.append(0);
                    continue;
                case 0://餘數等於除數,給對應商數位賦一,同時把餘數清零
                    quotient.append(1);
                    remainder.delete(0, remainder.length());
                    break;
                case 1://餘數大於除數
                    int remTemp[] = stringToIntArr(remainder.toString());//保存餘數的數組
                    int jTemp[] = new int[1];//把j轉換成數組以便運算
                    int proTemp[] = null;//保存j與b的乘積
                    for (int j = 1; j < 10; j++) {//最多隻能爲9
                        jTemp[0] = j;
                        proTemp = mulNum(jTemp, b);
                        int c = intArrCompaerTo(proTemp, remTemp);//保存除數乘商的積與餘數的大小比的值
                        if (c == -1 && j != 9) {//積大於餘數才繼續,並且在商爲9時即使積小於餘數也要往下執行
                            continue;
                        }
                        if ((c == -1 && j == 9) || c == 0) {
                            //當商爲9,積小於餘數時,或者積等於餘數時,不用將乘積的循環往前跳一次
                        } else {//將乘積的循環往前跳一次
                            jTemp[0] = --j;
                            proTemp = mulNum(jTemp, b);
                        }
                        quotient.append(j);//添加商
                        remainder.delete(0, remainder.length());//清空餘數
                        remainder.append(intArrToString(subNum(remTemp, proTemp)));//添加餘數減去積的差
                        break;
                    }
                    break;
            }
        }
        return flag ? stringToIntArr(quotient.toString()) : stringToIntArr(remainder.toString());
    }

    public BigNum rem(BigNum rem) throws Exception {
        int newNum[] = null;
        switch (compareTo(rem)) {//比較被除數與除數大小
            case -1://被除數小於除數時餘數就是被除數本身
                return this;
            case 0://被除數等於除數時餘數爲零
                newNum = new int[1];
                newNum[0] = 0;
                break;
            case 1://被除數大於除數
                newNum = divAndRem(NUM, rem.NUM, false);
                break;
        }
        return new BigNum(newNum, '+');
    }


java大數算法完成五則運算這系列文章到這裏也就結束了,有什麼想法或建議歡迎在下方評論區告訴我,最後,寫文不易~~點個贊吧!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章