搜尋

首頁  >  問答  >  主體

windows - Java高精度運算問題求救

公司專案裡面需要做大量的高精度運算,剛開始用double類型運算,後來發現用double類型運算後有些值的精確度超過了理想範圍,就用了BigDecimal來計算,現在的問題是BigDecimal的運算效率比double慢幾十倍,資料量大的話,慢的要死。請問有沒有好的解決方案?這個問題急需解決。

//相关性系数计算
public BigDecimal getRelativityTool_bydim(RelativityTool u) {
        BigDecimal sim = new BigDecimal("0"); //最后的皮尔逊相关度系数

        BigDecimal common_items_len = new BigDecimal(this.rating_map_list.size()); //操作数的个数

        BigDecimal this_sum = new BigDecimal("0"); //第一个相关数的和

        BigDecimal u_sum = new BigDecimal("0"); //第二个相关数的和

        BigDecimal this_sum_sq = new BigDecimal("0"); //第一个相关数的平方和

        BigDecimal u_sum_sq = new BigDecimal("0"); //第二个相关数的平方和

        BigDecimal p_sum = new BigDecimal("0"); //两个相关数乘积的和

        for (int i = 0; i < this.rating_map_list.size(); i++) {
            BigDecimal this_grade = this.rating_map_list.get(i);
            BigDecimal u_grade = u.rating_map_list.get(i);
            //评分求和                     //平方和                     //乘积和

            this_sum = this_sum.add(this_grade);
            u_sum = u_sum.add(u_grade);
            this_sum_sq = this_sum_sq.add(this_grade.pow(2));
            u_sum_sq = u_sum_sq.add(u_grade.pow(2));
            p_sum = p_sum.add(this_grade.multiply(u_grade));
        }
        BigDecimal num = common_items_len.multiply(p_sum).subtract(this_sum.multiply(u_sum));
        BigDecimal den = sqrt(common_items_len.multiply(this_sum_sq).subtract(this_sum.pow(2)).multiply(common_items_len.multiply(u_sum_sq).subtract(u_sum.pow(2))));
        if (den.compareTo(new BigDecimal("0")) == 0) {
            sim = new BigDecimal("1");
        } else {
            sim = num.pide(den,5, BigDecimal.ROUND_HALF_UP);
        }
        return sim;
    }
    //大数字开方
    public static BigDecimal sqrt(BigDecimal x) {
        BigDecimal n1 = BigDecimal.ONE;
        BigDecimal ans = BigDecimal.ZERO;
        while ((n1.multiply(n1).subtract(x)).abs().compareTo(BigDecimal.valueOf(0.001)) == 1) {
            BigDecimal s1 = x.pide(n1, 2000, BigDecimal.ROUND_HALF_UP);
            BigDecimal s2 = n1.add(s1);
            n1 = s2.pide(BigDecimal.valueOf(2), 2000, BigDecimal.ROUND_HALF_UP);

        }
        ans = n1;
        BigDecimal rt = new BigDecimal(ans.toString().split("\.")[0]);
        return rt;
    }
typechotypecho2733 天前939

全部回覆(3)我來回復

  • 怪我咯

    怪我咯2017-06-28 09:24:10

    除了使用C或C++來做高精度運算之外,好像沒有辦法同時兼顧效能和精確度了。

    回覆
    0
  • 扔个三星炸死你

    扔个三星炸死你2017-06-28 09:24:10

    大學計算機專業有門課程叫“計算方法”,專門探討如何在精度有限的計算過程中保持誤差最小化。樓主有興趣的話可以找下相關教材。

    回覆
    0
  • 欧阳克

    欧阳克2017-06-28 09:24:10

    後來發現用double型運算後有些值的精確度超過了理想範圍
    是超過還是滿足不了?

    這裡有一段計算平方根的程式碼,我從stackoverflow上找到的,在我自己的機子測試要比你上面那個快十倍左右。
    所以: 一則你可以透過改進的演算法來提高性能,其二,最好的辦法找一些已有的library來直接用:例如這個上面列的

    public void test_sqrt() {
        BigDecimal x = BigDecimal.valueOf(Long.MAX_VALUE);
        BigDecimal x0 = BigDecimal.ZERO;
        BigDecimal x2 = new BigDecimal(2);
        BigDecimal x1 = new BigDecimal(Math.sqrt(x.doubleValue()));
        while (!x0.equals(x1)) {
            x0 = x1;
            x1 = x.pide(x0, 2000, BigDecimal.ROUND_HALF_UP);
            x1 = x1.add(x0);
            x1 = x1.pide(x2, 2000, BigDecimal.ROUND_HALF_UP);
        }
        assertEquals(3037000499L, x1.longValue());
    }

    回覆
    0
  • 取消回覆