JavaRush /Java Blog /Random-TW /Java 中的 BigDecimal

Java 中的 BigDecimal

在 Random-TW 群組發布
你好!在今天的講座中,我們將討論大數。不,關於真正大的。 之前,我們不只一次看到原始資料類型的值範圍表。它看起來像這樣:
原始型 記憶體大小 數值範圍
位元組 8位 -128 至 127
短的 16位 至 -32768 至 32767
字元 16位 從 0 到 65536
整數 32位 從-2147483648 到 2147483647
長的 64位 從-9223372036854775808到9223372036854775807
漂浮 32位 從 (2 的 -149 次方) 到 ((2-2 的 -23 次方)*2 的 127 次方)
雙倍的 64位 由 (-2 的 63 次方) 到 ((2 的 63 次方) - 1)
布林值 8(用於數組時)、32(用於非數組時) 對或錯
如果我們談論整數,最大容量的資料類型是long,而當我們談論浮點數時,最大容量的資料類型是 double。但是,如果我們需要的數字太大,甚至無法放入long呢?可能的 Long 值的範圍相當大,但仍限制在一定的大小 - 64 位元。如果我們的超大數有 100 位,我們能得到什麼結果?幸運的是,您不需要發明任何東西。在 Java 中,為這種情況創建了兩個特殊的類別 - BigInteger(用於整數)和BigDecimal(用於浮點數)。他們的特點是什麼?首先,理論上它們沒有最大尺寸。理論上,因為不存在具有無限內存的計算機。而如果你在程式中建立的數字大於電腦記憶體的大小,當然程式將無法運作。但這種情況不太可能發生。因此,我們可以說數字的大小實際上BigIntegerBigDecimal無限的。這些類別是用來做什麼的?首先,對於精度要求極高的計算。例如,在某些程式中,人的生命可能取決於計算的準確性(飛機和火箭或醫療設備的軟體)。因此,如果連小數點後150位也發揮重要作用,BigDecimal那麼它就是最好的選擇。此外,這些物件經常用於金融領域,其中最小數值的計算精度也極為重要。 如何使用物件BigInteger以及BigDecimal需要記住的重要事項是什麼? 這些類別的物件是這樣創建的:
public class Main {

   public static void main(String[] args) {

       BigInteger integer = new BigInteger("11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111");
       System.out.println(integer);

       BigDecimal decimal = new BigDecimal("123.444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444");
       System.out.println(decimal);
   }
}
將字串作為參數傳遞只是可能的建構函數之一。Here we use strings because our numbers exceed the maximum values long​​and double, and somehow we need to explain to the compiler exactly what number we want to get :) Just pass the number 11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 to the constructor 1111111111111111111111111111111111111111111111111111111111111111111 will not work: Java will try to將傳遞的數字「適合」一種原始資料類型,但它不適合其中任何一種。因此,使用字串來傳遞所需的數字是一個不錯的選擇。這兩個類別都可以自動從傳遞的字串中提取數值。使用大量類別時要記住的另一個要點是它們的物件是不可變的 ( Immutable)String透過類別和基元(Integer、Long 等)的包裝類別 的範例,您已經非常熟悉不變性原則。
import java.math.BigInteger;

public class Main {

   public static void main(String[] args) {

       BigInteger integer = new BigInteger("11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111");
       System.out.println(integer);

       integer.add(BigInteger.valueOf(33333333));
       System.out.println(integer);

   }
}
控制台輸出:

1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111
正如您所期望的,我們的數字沒有改變。為了使加法操作成功,您必須建立一個新物件並將加法結果指派給它。
import java.math.BigInteger;

public class Main {

   public static void main(String[] args) {

       BigInteger integer = new BigInteger("11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111");
       System.out.println(integer);

       BigInteger result = integer.add(BigInteger.valueOf(33333333));
       System.out.println(result);

   }
}
控制台輸出:

1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111144444444
現在一切都正常了:) 順便說一句,您是否注意到加法操作看起來有多不尋常?
BigInteger result = integer.add(BigInteger.valueOf(33333333));
這是另一個重要的一點。大量類別在其操作中不使用 +-*/ 運算符,而是提供一組方法。 讓我們來看看主要的方法(您可以一如既往地在 Oracle 文件中找到完整的方法清單:此處此處)。
  1. 執行算術運算的方法: add()subtract()multiply()divide()。分別用於加、減、乘、除運算。

  2. doubleValue()intValue()floatValue()longValue()ETC。- 用於將大量數字轉換為 Java 基本類型。使用時要小心,記住容量的差異!

    import java.math.BigInteger;
    
    public class Main {
    
       public static void main(String[] args) {
    
           BigInteger integer = new BigInteger("11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111");
    
           long result = integer.longValue();
           System.out.println(result);
    
       }
    }

    控制台輸出:

    
    8198552921648689607
  3. min()max()- 允許您找到傳遞的兩個大數的最小值和最大值。
    請注意:方法不是靜態的!

    import java.math.BigInteger;
    
    public class Main {
    
       public static void main(String[] args) {
    
           BigInteger integer = new BigInteger("11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111");
           BigInteger integer2 = new BigInteger("222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222");
    
           System.out.println(integer.max(integer2));
    
       }
    }

    控制台輸出:

    
    222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222

BigDecimal 捨入控制

這個主題包含在一個單獨的部分中,因為對大數進行舍入和調整並不是一件簡單的事情。BigDecimal您可以使用 來設定數字的小數位數setScale()。例如,我們要將數字111.5555555555的精度設定為小數點後三位。但是,我們將無法將數字 3 作為參數傳遞給該方法setScale(),從而解決我們的問題。如上所述,BigDecimal這些是用於提高精度的計算的數字。在目前的形式中,我們的數字有 10 位小數。我們想丟棄其中的 7 個,只留下 3 個。因此,除了數字 3 之外,我們還必須將舍入模式作為參數傳遞共有8種舍入模式BigDecimal非常多!但如果您需要真正微調程式中的運算精度,您將擁有所需的一切。因此,以下是 中可用的 8 種舍入模式BigDecimal
  1. ROUND_CEILING- 圍捕

    111.5555555555 -> setScale(3, ROUND_CEILING) -> 111.556
  2. ROUND_DOWN- 排放丟棄

    111.5555555555 -> setScale(3, ROUND_DOWN) -> 111.555
  3. ROUND_FLOOR- 向下舍入

    111.5555555555 -> setScale(3, ROUND_FLOOR) -> 111.555

  4. ROUND_HALF_UP— 若小數點後的數字 >= .5,則四捨五入

    0.55 -> setScale(1, ROUND_HALF_UP) -> 0.6
    0.54 -> setScale(1, ROUND_HALF_UP) -> 0.5
  5. ROUND_HALF_DOWN— 若小數點後的數字 > .5,則四捨五入

    0.55 -> setScale(1, ROUND_HALF_DOWN) -> 0.5
    0.56 -> setScale(1, ROUND_HALF_DOWN) -> 0.6
  6. ROUND_HALF_EVEN— 四捨五入取決於小數點左邊的數字。如果左邊的數字是偶數,則向下捨去。如果小數點左邊的數字是奇數,則四捨五入。

    2.5 -> setScale(0, ROUND_HALF_EVEN) -> 2

    小數點左邊的數字 - 2 - 是偶數。向下舍入。由於我們要求小數點後 0 位,因此結果將為 2。

    3.5 -> setScale(0, ROUND_HALF_EVEN) -> 4

    小數點左邊的數字 - 3 - 是奇數。向上舍入。由於我們要求小數點後 0 位,因此結果將為 4。

  7. ROUND_UNNECCESSARY— 用於需要將舍入模式傳遞給某種方法,但數字不需要捨入的情況。如果在設定 ROUND_UNNECCESSARY 模式時嘗試對數字進行舍入,則會引發 ArithmeticException。

    3.51 -> setScale(1, ROUND_UNNECCESSARY) -> ArithmeticException
  8. ROUND_UP- 圍捕。

    111.5551 -> setScale(3, ROUND_UP) -> 111.556

大數比較

這個問題也很重要。您已經記得該方法用於比較 Java 中的物件equals()。它要么由語言本身提供(對於 Java 的內建類別),要么由程式設計師覆蓋。但對於類別物件的情況,不建議BigDecimal使用此方法equals()進行比較。原因是只有當BigDecimal.equals()兩個數字有相同的值和小數位數時,雙數方法才會回傳true :讓我們比較一下y和 y方法的行為: equals()DoubleBigDecimal
import java.math.BigDecimal;

public class Main {

   public static void main(String[] args) {

       Double a = 1.5;
       Double b = 1.50;

       System.out.println(a.equals(b));

       BigDecimal x = new BigDecimal("1.5");
       BigDecimal y = new BigDecimal("1.50");

       System.out.println(x.equals(y));

   }
}
控制台輸出:

true
false
正如您所看到的,在 c 的情況下,數字 1.5 和 1.50BigDecimal原來是不相等的!equals()發生這種情況正是因為類別中方法的特殊性BigDecimal。為了更正確地比較兩者,BigDecimal最好使用以下方法compareTo()
import java.math.BigDecimal;

public class Main {

   public static void main(String[] args) {

       BigDecimal x = new BigDecimal("1.5");
       BigDecimal y = new BigDecimal("1.50");

       System.out.println(x.compareTo(y));

   }
}
控制台輸出:

0
該方法compareTo()傳回 0,這意味著等於 1.5 和 1.50。這就是我們所指望的結果!:) 今天的課程到此結束。是時候回去執行任務了!:)
留言
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION