你好!在今天的課程中,我們將討論大數。不,我的意思是真的很大。我們以前多次遇到原始數據類型的值範圍表。它看起來像這樣:
最寬敞的整數數據類型是long。說到浮點數,那就是double。但是,如果我們需要的數字大到連long都裝不下怎麼辦?Long 數據類型具有相當大的可能值範圍,但仍限於 64 位。如果我們的超大數需要 100 位,我們需要想出什麼?幸運的是,我們不需要發明任何東西。對於這種情況,Java 有兩個特殊類:BigInteger(用於整數)和BigDecimal(對於浮點數)。是什麼讓他們與眾不同?首先,理論上,它們沒有最大尺寸。我們說“理論上”,因為沒有無限內存的計算機。如果您的程序創建的數字大於可用內存量,那麼該程序當然將無法運行。但這種情況不太可能發生。因此,我們可以說BigInteger和BigDecimal可以表示幾乎無限大小的數字。這些類有什麼用?首先,對於精度要求極其嚴格的計算。例如,人的生命可能取決於某些程序(例如控制飛機、火箭或醫療設備的軟件)中計算的準確性。所以如果第 150 位小數很重要,那麼BigDecimal是最好的選擇。此外,此類對象經常用於金融領域,即使是最小值的準確計算也非常重要。您如何使用BigInteger和BigDecimal對象,您是否需要了解它們?這些類的對像是這樣創建的:
原始類型 | 內存大小 | 取值範圍 |
---|---|---|
字節 | 8位 | -128 到 127 |
短的 | 16位 | -32768 至 32767 |
字符 | 16位 | 0 到 65536 |
整數 | 32位 | -2147483648 至 2147483647 |
長的 | 64位 | -9223372036854775808 至 9223372036854775807 |
漂浮 | 32位 | (2 的 -149 次方) 到 ((2 的 -23 次方) * 2 的 127 次方) |
雙倍的 | 64位 | (-2 的 63 次方) 到 ((2 的 63 次方) - 1) |
布爾值 | 8(用於數組時),32(不用於數組時) | 對或錯 |
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);
}
}
將字符串傳遞給構造函數只是一種可能的選擇。這裡我們使用字符串,因為我們的數字超過了long和double的最大值,我們確實需要一些方法來向編譯器解釋我們要創建哪個數字 :) 只需傳遞數字 111111111111111111111111111111111111111111111111111111111111111111111 1111111111111111111111111111111111111111111111111111111111111111111 到構造函數將不起作用:Java 將嘗試將傳遞的數字填充到一種原始數據類型中,但它不適合其中任何一種。這就是為什麼使用字符串傳遞所需數字是一個不錯的選擇。這兩個類都可以自動從傳遞的字符串中提取數值。使用大數類時要記住的另一個要點是它們的對像是不可變的 ( 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);
}
}
控制台輸出:
11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111
如您所料,我們的號碼沒有改變。要執行加法運算,您必須創建一個新對象來接收運算結果。
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);
}
}
控制台輸出:
11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111144444444
看,現在一切正常了 :) 順便說一下,您是否注意到加法運算看起來有多麼不尋常?
BigInteger result = integer.add(BigInteger.valueOf(33333333));
這是另一個重點。大數類不使用 + - * / 運算符。相反,它們提供了一組方法。讓我們熟悉一下主要方法(一如既往,您可以在 Oracle 文檔中找到完整的方法列表:此處和此處)。
-
算術運算方法:add()、subtract()、multiply()、divide()。這些方法分別用於執行加法、減法、乘法和除法。
-
doubleValue()、intValue()、floatValue()、longValue()等用於將大數轉換為 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
-
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 舍入行為
本主題有其單獨的部分,因為對大數字進行舍入和配置舍入行為並不是那麼簡單。您可以使用setScale()方法設置BigDecimal的小數位數。例如,假設我們希望數字111.5555555555 的小數點後保留三位數字。但是,我們不能通過將數字 3 作為參數傳遞給setScale()方法來實現我們想要的。如上所述,BigDecimal用於表示對計算精度有嚴格要求的數字。在當前形式中,我們的數字在小數點後有 10 位數字。我們要去掉其中的 7 個,只保留 3 個。因此,除了數字 3 之外,我們還必須通過舍入模式。 BigDecimal共有 8 種舍入模式。好多啊!但是,如果您真的需要微調計算的精度,您將擁有所需的一切。因此,這是BigDecimal提供的 8 種舍入模式:-
ROUND_CEILING — 向上舍入
111.5555555555 -> setScale(3, ROUND_CEILING) -> 111.556
-
ROUND_DOWN — 向零舍入
111.5555555555 -> setScale(3, ROUND_DOWN) -> 111.555
-
ROUND_FLOOR — 向下舍入
111.5555555555 -> setScale(3, ROUND_FLOOR) -> 111.555
-
ROUND_HALF_UP — 如果小數點後的數字 >= 0.5,則向上舍入
0.55 -> setScale(1, ROUND_HALF_UP) -> 0.6 0.54 -> setScale(1, ROUND_HALF_UP) -> 0.5
-
ROUND_HALF_DOWN — 如果小數點後的數字 > 0.5,則向上舍入
0.55 -> setScale(1, ROUND_HALF_DOWN) -> 0.5 0.56 -> setScale(1, ROUND_HALF_DOWN) -> 0.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。
-
ROUND_UNNECCESSARY — 當您必須將舍入模式傳遞給方法但不需要捨入數字時使用此模式。如果您嘗試使用 ROUND_UNNECCESSARY 模式集對數字進行舍入,則會拋出 ArithmeticException。
3.51 -> setScale(1, ROUND_UNNECCESSARY) -> ArithmeticException
-
ROUND_UP — 從零舍入。
111.5551 -> setScale(3, ROUND_UP) -> 111.556
比較大的數字
這也很重要。你會記得我們使用equals()方法來比較 Java 中的對象。實現要么由語言本身提供(對於標準 Java 類),要么由程序員覆蓋。但對於BigDecimal對象,不建議使用equals()方法進行比較。這是因為BigDecimal.equals()方法僅在 2 個數字具有相同的值和比例時才返回 true:讓我們比較Double和BigDecimal類的equals()方法的行為:
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
如您所見,對於BigDecimal,數字 1.5 和 1.50 結果是不相等的!這正是因為BigDecimal類中equals()方法的實現細節。為了更準確地比較兩個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 相等。而這正是我們所期望的結果!:) 今天的課程到此結束。現在是時候回到任務了!:)
GO TO FULL VERSION