Java 高精度的大數字運算

來源:互聯網
上載者:User

標籤:java   大數字計算   

      為瞭解決Java基礎資料型別 (Elementary Data Type)在運算時會出現的溢出和計算不精確的問題。Java 提供了兩個類BigInteger和BigDecimal,專門用於進行高精度運算。凡是能用int 或float 做的事情,用BigInteger和BigDecimal也可以做,只是必須換用方法調用,而不是使用運算子。
高精度整數BigInteger
      BigInteger支援任意精度的整數,也就是說我們可精確表示任意大小的整數值;同時在運算過程中不會丟失任何資訊;
高精度浮點數BigDecimal

      它可以表示任意精度的小數,並對它們進行計算。由於 BigDecimal 對象是不可變的,這些方法中的每一個都會產生新的 BigDecimal 對象。因此,因為建立對象的開銷,BigDecimal 不適合於大量的數學計算,但設計它的目的是用來精確地表示小數。

import java.math.BigDecimal;import java.math.BigInteger;public class BigNumber {//預設除法運算精度,即保留小數點多少位 private static final int DEFAULT_DIV_SCALE = 10;//這個類不能執行個體化 private BigNumber() {}/** * 提供精確的加法運算。 * @param v1 被加數 * @param v2 加數 * @return 兩個參數的和 */public static double add(double v1, double v2) {   BigDecimal b1 = new BigDecimal(Double.toString(v1));   BigDecimal b2 = new BigDecimal(Double.toString(v2));   return (b1.add(b2)).doubleValue();}/** * 提供精確的減法運算。 * @param v1 被減數 * @param v2 減數 * @return 兩個參數的差 */public static double sub(double v1, double v2) {   BigDecimal b1 = new BigDecimal(Double.toString(v1));   BigDecimal b2 = new BigDecimal(Double.toString(v2));   return (b1.subtract(b2)).doubleValue();}/** * 提供精確的乘法運算。 * @param v1 被乘數 * @param v2 乘數 * @return 兩個參數的積 */public static double mul(double v1, double v2) {   BigDecimal b1 = new BigDecimal(Double.toString(v1));   BigDecimal b2 = new BigDecimal(Double.toString(v2));   return (b1.multiply(b2)).doubleValue();}/** * 提供(相對)精確的除法運算,當發生除不盡的情況時,精確到 * 小數點以後多少位,以後的數字四捨五入。 * @param v1 被除數 * @param v2 除數 * @return 兩個參數的商 */public static double div(double v1, double v2) {   return div(v1, v2, DEFAULT_DIV_SCALE);}/** * 提供(相對)精確的除法運算。當發生除不盡的情況時,由scale參數指 * 定精度,以後的數字四捨五入。 * @param v1 被除數 * @param v2 除數 * @param scale 表示需要精確到小數點以後幾位。 * @return 兩個參數的商 */public static double div(double v1, double v2, int scale) {   if (scale < 0) {    System.err.println("除法精度必須大於0!");    return 0;   }   BigDecimal b1 = new BigDecimal(Double.toString(v1));   BigDecimal b2 = new BigDecimal(Double.toString(v2));   return (b1.divide(b2, scale, BigDecimal.ROUND_HALF_UP)).doubleValue();}/*** 計算Factorial階乘!* @param n   任意大於等於0的int* @return     n!的值*/public static BigInteger getFactorial(int n) {   if (n < 0) {    System.err.println("n必須大於等於0!");    return new BigInteger("-1");   } else if (n == 0) {    return new BigInteger("0");   }   //將數組換成字串後構造BigInteger   BigInteger result = new BigInteger("1");   for (; n > 0; n--) {    //將數字n轉換成字串後,再構造一個BigInteger對象,與現有結果做乘法    result = result.multiply(new BigInteger(new Integer(n).toString()));   }   return result;}public static void main(String[] args) {   //   如果我們編譯運行下面這個程式會看到什嗎?   System.out.println(0.05 + 0.01);   System.out.println(1.0 - 0.42);   System.out.println(4.015 * 100);   System.out.println(123.3 / 100);   //   0.060000000000000005   //   0.5800000000000001   //   401.49999999999994   //   1.2329999999999999   //計算階乘,可以將n設得更大   int n = 30;   System.out.println("計算n的階乘" + n + "! = " + BigNumber.getFactorial(n));   //用double構造BigDecimal   BigDecimal bd1 = new BigDecimal(0.1);   System.out.println("(bd1 = new BigDecimal(0.1)) = " + bd1.toString());   //用String構造BigDecimal   BigDecimal bd2 = new BigDecimal("0.1");   System.out.println("(bd2 = new BigDecimal(\"0.1\")) = "     + bd2.toString());   BigDecimal bd3 = new BigDecimal("0.10");   //equals方法比較兩個BigDecimal對象是否相等,相等返回true,不等返回false   System.out.println("bd2.equals(bd3) = " + bd2.equals(bd3));//false   //compareTo方法比較兩個BigDecimal對象的大小,相等返回0,小於返回-1,大於返回1。   System.out.println("bd2.compareTo(bd3) = " + bd2.compareTo(bd3));//0   //進行精確計算   System.out.println("0.05 + 0.01 = " + BigNumber.add(0.05, 0.01));   System.out.println("1.0 - 0.42 = " + BigNumber.sub(1.0, 0.42));   System.out.println("4.015 * 100 =" + BigNumber.mul(4.015, 100));   System.out.println("123.3 / 100 = " + BigNumber.div(123.3, 100));   }}

      (1)BigInteger和BigDecimal都是不可變(immutable)的,在進行每一步運算時,都會產生一個新的對象,由於建立對象會引起開銷,它們不適合於大量的數學計算,應盡量用long,float,double等基本類型做科學計算或者工程計算。
設計BigInteger和BigDecimal的目的是用來精確地表示大整數和小數,使用於在商業計算中使用。
      (2)BigDecimal有4個夠造方法,其中的兩個用BigInteger構造,另一個是用double構造,還有一個使用String構造。
應該避免使用double構造BigDecimal,因為:有些數字用double根本無法精確表示,傳給BigDecimal構造方法時就已經不精確了。比如,new BigDecimal(0.1)得到的值是0.1000000000000000055511151231257827021181583404541015625。
使用new BigDecimal("0.1")得到的值是0.1。因此,如果需要精確計算,用String構造BigDecimal,避免用double構造,儘管它看起來更簡單!
      (3)equals()方法認為0.1和0.1是相等的,返回true,而認為0.10和0.1是不等的,結果返回false。方法compareTo()則認為0.1與0.1相等,0.10與0.1也相等。所以在從數值上比較兩個BigDecimal值時,應該使用 compareTo()而不是 equals()。
      (4)另外還有一些情形,任意精度的小數運算仍不能表示精確結果。例如,1除以9會產生無限迴圈的小數 .111111...。
出於這個原因,在進行除法運算時,BigDecimal可以讓您顯式地控制舍入。

運算結果:

0.0600000000000000050.5800000000000001401.499999999999941.2329999999999999計算n的階乘30! = 265252859812191058636308480000000(bd1 = new BigDecimal(0.1)) = 0.1000000000000000055511151231257827021181583404541015625(bd2 = new BigDecimal("0.1")) = 0.1bd2.equals(bd3) = falsebd2.compareTo(bd3) = 00.05 + 0.01 = 0.061.0 - 0.42 = 1.424.015 * 100 =104.015123.3 / 100 = 223.3

Java 高精度的大數字運算

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.