Java 中檢查 double 是否為整數
1. 概述
處理數值資料通常需要精確處理。當我們需要檢查double
是否實際上是一個數學整數時,就會出現一個常見的情況。
在本教程中,我們將探索可用於執行此檢查的各種技術,以確保我們的數值評估的準確性和靈活性。
2.問題介紹
首先,眾所周知, double
是一種浮點資料類型,可以表示小數值,並且具有比 Java int
或Integer
更廣泛的範圍.
另一方面,數學整數是不能儲存小數值的整數資料型別。
當小數點後的值可以忽略或不存在時, double
精度數可以被視為表示數字整數。這表示**double
保存的是沒有任何小數部分的整數**。例如, 42.0D
實際上是一個整數 ( 42
)。然而, 42.42D
則不然。
在本教程中,我們將學習幾種檢查double
數是否為數學整數的方法。
3. 特殊的Double
精度值: NaN
和 Infinity
在我們深入檢查double
是否為整數之前,我們先來看看一些特殊的 double 值: Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY,
和Double.NaN.
Double.NaN
表示該數值「不是數字」。因此,它也不是整數。
另一方面, Double.POSITIVE_INFINITY
和Double.NEGATIVE_INFINITY
都不是傳統意義上的具體數字。它們代表無窮大,這是一個特殊值,表示數學運算的結果超出了雙精度浮點數的最大可表示有限值。因此,這兩個無窮大值也不是整數。
此外, Double
類別也提供isNan()
和isInfinite()
方法來判斷Double
物件是 NaN 還是無限。因此,在檢查double
是否為整數之前,我們可以先執行這些特殊值檢查。
為簡單起見,我們創建一個方法來執行此任務,以便可以在我們的程式碼範例中重複使用它:
boolean notNaNOrInfinity(double d) {
return !(Double.isNaN(d) || Double.isInfinite(d));
}
4. 將double
轉換為int
要確定double
是否為整數,最直接的想法可能是先將double
轉換為int
,然後將轉換後的int
與原始**double** .
如果它們的值相等, double
是整數。
接下來,我們來實作並測試這個想法:
double d1 = 42.0D;
boolean d1IsInteger = notNaNOrInfinity(d1) && (int) d1 == d1;
assertTrue(d1IsInteger);
double d2 = 42.42D;
boolean d2IsInteger = notNaNOrInfinity(d2) && (int) d2 == d2;
assertFalse(d2IsInteger);
如測試所示,這種方法可以完成任務。
然而,正如我們所知,Java 中**ouble'
範圍比int
更寬**。因此,讓我們寫一個測試來檢查如果double
超出int
範圍會發生什麼:
double d3 = 2.0D * Integer.MAX_VALUE;
boolean d3IsInteger = notNaNOrInfinity(d3) && (int) d3 == d3;
assertTrue(!d3IsInteger); // <-- fails if exceeding Integer's range
在此測試中,我們將2.0D * Integer.MAX_VALUE
指派給double d3.
顯然,這個值是一個數學整數,但超出了Java的整數範圍。因此,事實證明,如果給定的double
超出了 Java 整數的範圍,這種方法將不起作用。
接下來,讓我們來探索解決double
超出整數範圍的情況的替代解決方案。
5. 使用模運算子“ %
”
我們已經提到過,如果double
是整數,則它沒有小數部分。因此,我們可以測試double
是否能被1
整除。為此,我們可以使用模運算子:
double d1 = 42.0D;
boolean d1IsInteger = notNaNOrInfinity(d1) && (d1 % 1) == 0;
assertTrue(d1IsInteger);
double d2 = 42.42D;
boolean d2IsInteger = notNaNOrInfinity(d2) && (d2 % 1) == 0;
assertFalse(d2IsInteger);
double d3 = 2.0D * Integer.MAX_VALUE;
boolean d3IsInteger = notNaNOrInfinity(d3) && (d3 % 1) == 0;
assertTrue(d3IsInteger);
如測試所示,即使double
數超出整數範圍,此方法也有效。
6. double
標準Math
類別提供了一系列舍入方法:
-
ceil()
– 例:ceil(42.0001) = 43; ceil(42.999) = 43
-
floor()
– 例:floor(42.0001) = 42; floor(42.9999)
= 42
-
round()
– 範例:round(42.4) = 42; round(42.5) = 43
-
rint()
– 例:rint(42.4) = 42; rint(42.5) = 43
我們不會詳細介紹清單中的Math
舍入方法。所有這些方法都有一個共同的特徵:它們將提供的double
舍入為接近的數學整數。
**如果double
表示數學整數,則將其傳遞給上面列表中的任何舍入方法後,結果必須等於輸入double,
**例如:
-
ceil(42.0) = 42
-
floor(42.0) = 42
-
round(42.0) = 42
-
rint(42.0) = 42
因此,我們可以使用任何舍入方法來執行檢查。
接下來,我們以Math.floor()
為例來示範這是如何完成的:
double d1 = 42.0D;
boolean d1IsInteger = notNaNOrInfinity(d1) && Math.floor(d1) == d1;
assertTrue(d1IsInteger);
double d2 = 42.42D;
boolean d2IsInteger = notNaNOrInfinity(d2) && Math.floor(d2) == d2;
assertFalse(d2IsInteger);
double d3 = 2.0D * Integer.MAX_VALUE;
boolean d3IsInteger = notNaNOrInfinity(d3) && Math.floor(d3) == d3;
assertTrue(d3IsInteger);
測試結果表明,即使double
超出整數範圍,該解決方案仍然有效。
當然,如果我們願意,我們可以用ceil(), round(),
或rint().
來取代floor()
方法。
7. 使用番石榴
Guava 是一個廣泛使用的常用實用程式開源程式庫。 Guava 的DoubleMath
類別提供了isMathematicalInteger()
方法。方法名稱暗示這正是我們正在尋找的解決方案。
要包含 Guava,我們需要將其依賴項新增到pom.xml
中:
<span class="hljs-tag"><<span class="hljs-name">dependency</span>></span> <span class="hljs-tag"><<span class="hljs-name">groupId</span>></span>com.google.guava<span class="hljs-tag"></<span class="hljs-name">groupId</span>></span> <span class="hljs-tag"><<span class="hljs-name">artifactId</span>></span>guava<span class="hljs-tag"></<span class="hljs-name">artifactId</span>></span> <span class="hljs-tag"><<span class="hljs-name">version</span>></span>32.1.3-jre<span class="hljs-tag"></<span class="hljs-name">version</span>></span> <span class="hljs-tag"></<span class="hljs-name">dependency</span>></span>
最新版本資訊可以在Maven Repository上找到。
接下來,讓我們寫一個測試來驗證DoubleMath.isMathematicalInteger()
是否如預期般運作:
double d1 = 42.0D;
boolean d1IsInteger = DoubleMath.isMathematicalInteger(d1);
assertTrue(d1IsInteger);
double d2 = 42.42D;
boolean d2IsInteger = DoubleMath.isMathematicalInteger(d2);
assertFalse(d2IsInteger);
double d3 = 2.0D * Integer.MAX_VALUE;
boolean d3IsInteger = DoubleMath.isMathematicalInteger(d3);
assertTrue(d3IsInteger);
測試結果表明,無論輸入的double
是在 Java 整數範圍之內還是之外,該方法都能始終產生預期結果。
敏銳的眼睛可能已經注意到,我們在上面的測試中沒有調用notNaNOrInfinity()
進行NaN
和無窮大檢查。這是因為**DoubleMath.isMathematicalInteger()
方法也處理NaN
和無窮大:**
boolean isInfinityInt = DoubleMath.isMathematicalInteger(Double.POSITIVE_INFINITY);
assertFalse(isInfinityInt);
boolean isNanInt = DoubleMath.isMathematicalInteger(Double.NaN);
assertFalse(isNanInt);
八、結論
在本文中,我們首先討論了「 double
代表數學整數」的意思。然後,我們探索了不同的方法來檢查double
精度數是否確實符合數學整數的條件。
雖然將double
直接轉換為int
(即theDouble == (int) theDouble
)看起來可能很直觀,但其限制在於無法處理theDouble
超出 Java 整數範圍的情況。
為了解決這個限制,我們研究了取模和舍入方法,它們可以正確處理值超出整數範圍的double
。此外,我們也示範了 Guava 中的DoubleMath.isMathematicalInteger()
方法,作為我們問題的附加、穩健的解決方案。
與往常一樣,範例的完整原始程式碼可在 GitHub 上取得。