Math – Guava的數學工具包
這個包中含有各種各樣的數學工具類,比 JDK 更優化, 測試更完善
Contents 綜述
- Guava Math 提供了爲基本數據類型而設計的獨立的類[
IntMath
],[LongMath
],
[DoubleMath
], 和 [BigIntegerMath
], 這些類具有這相互平行的結構,
他們的方法都是基於相應數據類型而進行實現.
**請注意: 在com.google.common.primitives
包中, 有一些函數或者類可能看起來不那麼的’數學’,
比如 [Ints
].** - Guava 爲單個或者成對的數據集提供了各種統計計算的方法(比如求平均值,中位數等等).
如果想使用 Guava Math 包,請先閱讀這個指南Stats 而不是去閱讀 Java DOC. - [
LinearTransformation
] 代表着y = mx + b(這是個一次函數)
中的線性變換;
比如英尺和米之間的換算(英尺 = 米 * 3.2808399 ), 或者開氏溫度與華氏溫度之間的換算(℉ = 1.8 * K - 459.67 ).
Examples 舉個栗子
int logFloor = LongMath.log2(n, FLOOR);
int mustNotOverflow = IntMath.checkedMultiply(x, y);
long quotient = LongMath.divide(knownMultipleOfThree, 3, RoundingMode.UNNECESSARY); // fail fast on non-multiple of 3
BigInteger nearestInteger = DoubleMath.roundToBigInteger(d, RoundingMode.HALF_EVEN);
BigInteger sideLength = BigIntegerMath.sqrt(area, CEILING);
Why use these? 爲什麼使用這些工具類?
- Guava Math的工具類爲很多不常見的溢出情況都做了充分的測試. 溢出的語義也在相關的文檔中進行了清晰的定義.
如果預檢查不能通過, 則快速的返回失敗(異常). - Guava Math 已經進行了基準測試和最佳的優化, 儘管因爲不同的硬件原因會造成不可避免的性能差異,
但是 Guava Math 通常情況下的運行速度與Apache Commons
的MathUtils
互相媲美,
在某些場景下, Guava Math 甚至更優. - 這些類在設計之初就考慮到了代碼的可讀性、幫助養成好的編碼習慣。
比如IntMath.log2(x, CEILING)
在你進行快速瀏覽代碼的時候也能清晰快速的瞭解它的含義,
而32 - Integer.numberOfLeadingZeros(x - 1)
在你不查看API的情況下就很難理解
(而它,實際上表示x-1轉換爲32位二進制補碼之後,最高有值位前0的個數)。
注意: 這些類與 GWT 不兼容的,他們也不都是 GWT 的優化, 原因是他們有不同的計算溢出邏輯。
Math on Integral Types 整型數值計算
對於整數, Math工具包主要處理三種整數類型值的計算: int
, long
, 和 BigInteger
。
其中的工具類被合理的命名爲[IntMath
], [LongMath
], 和 [BigIntegerMath
].
Checked Arithmetic 檢查方法
Guava Math 爲 IntMath
和 LongMath
計算中可能的一些結果溢出情況提供了一些運算方法,
這些方法將導致有結果溢出的計算 快速失敗 而不是忽略掉溢出。
IntMath |
LongMath |
---|---|
[IntMath.checkedAdd ] |
[LongMath.checkedAdd ] |
[IntMath.checkedSubtract ] |
[LongMath.checkedSubtract ] |
[IntMath.checkedMultiply ] |
[LongMath.checkedMultiply ] |
[IntMath.checkedPow ] |
[LongMath.checkedPow ] |
// 舉個栗子
IntMath.checkedAdd(Integer.MAX_VALUE, Integer.MAX_VALUE); // 拋出 ArithmeticException 異常.
Real-valued methods 實數運算
IntMath
, LongMath
和 BigIntegerMath
提供了很多實數運算的方法, 但是他們都會將結果取整.
這些方法接受一個 [java.math.RoundingMode
] 枚舉值用作取整的類型, 這枚舉值和 JDK 中的 RoundingMode
相同,
並且遵循着以下規則:
DOWN
: 向下取整. (與Java除法的行爲相同, 比如 Java 中計算 5 / 2 = 2.)UP
: 向上取整(即 5 / 2 = 3).FLOOR
: 向着0的負無窮的方向取整(實際檢驗中,此枚舉類結果爲 5 / 2 = 2,與 DOWN 相同,具體區別有待驗證).CEILING
: 向着0的正無窮方向取整(實際檢驗中,此枚舉類結果爲 5 / 2 = 3,與 UP 相同,具體區別有待驗證).UNNECESSARY
: 無需取整,若如此做,將會拋出一個ArithmeticException
異常並快速失敗.HALF_UP
: 四捨五入,0.5的話向前進1( 5 / 2 = 3).HALF_DOWN
: 特殊的四捨五入,大於0.5進1,等於小於0.5爲0(5 / 2 = 2).HALF_EVEN
: 特殊的四捨五入,0.5會進位到最相鄰的偶數,大於0.5則進位。
(_注:HALF_EVEN:我們用 12 與 13 除以 5 舉例, 12 / 5 = 2.5 那麼 HALF_EVEN 返回的就是 2, 13 / 5 = 2.6 那麼 HALF_EVEN 返回 3.
特殊的: 21 / 6 = 3.5 進位到最相鄰的偶數,那麼返回 4_)。
這些方法在被使用時應該是具有良好可讀性的, 例如: divide(x, 3, CEILING)
的語義在快速通讀瀏覽的情況下也是非常清晰的。
此外, 除了 sqrt
之外, 這些方法的內部採用整數計算進行實現,
而在 sqrt
中, 則是先構建構建初始近似值(先進行浮點數計算).
Operation | IntMath |
LongMath |
BigIntegerMath |
---|---|---|---|
Division | [divide(int, int, RoundingMode) ] |
[divide(long, long, RoundingMode) ] |
[divide(BigInteger, BigInteger, RoundingMode) ] |
Base-2 logarithm | [log2(int, RoundingMode) ] |
[log2(long, RoundingMode) ] |
[log2(BigInteger, RoundingMode) ] |
Base-10 logarithm | [log10(int, RoundingMode) ] |
[log10(long, RoundingMode) ] |
[log10(BigInteger, RoundingMode) ] |
Square root | [sqrt(int, RoundingMode) ] |
[sqrt(long, RoundingMode) ] |
[sqrt(BigInteger, RoundingMode) ] |
BigIntegerMath.sqrt(BigInteger.TEN.pow(99), RoundingMode.HALF_EVEN);
// returns 31622776601683793319988935444327185337195551393252
Additional functions 其他方法
我們提供了一些額外的我們所發現的十分有用的一些數學方法(函數/工具/公式).
Operation 運算 | IntMath 整形計算 |
LongMath 長整型計算 |
BigIntegerMath 超大整形數據計算 |
---|---|---|---|
Greatest common divisor | [gcd(int, int) ] |
[gcd(long, long) ] |
In JDK: [BigInteger.gcd(BigInteger) ] |
Modulus (總是正值, -5 取模 3 返回 1) | [mod(int, int) ] |
[mod(long, long) ] |
In JDK: [BigInteger.mod(BigInteger) ] |
Exponentiation (may overflow) | [pow(int, int) ] |
[pow(long, int) ] |
In JDK: [BigInteger.pow(int) ] |
Power-of-two testing | [isPowerOfTwo(int) ] |
[isPowerOfTwo(long) ] |
[isPowerOfTwo(BigInteger) ] |
Factorial (如果輸入過大, 則返回最大值 MAX_VALUE ) |
[factorial(int) ][IntMath.factorial(int) ] |
[factorial(int) ][LongMath.factorial(int) ] |
[factorial(int) ][BigIntegerMath.factorial(int) ] |
Binomial coefficient (如果值過大, 則返回最大值 MAX_VALUE ) |
[binomial(int, int) ][IntMath.binomial(int, int) ] |
[binomial(int, int) ][LongMath.binomial(int, int) ] |
[binomial(int, int) ][BigIntegerMath.binomial(int, int) ] |
Floating-point arithmetic 浮點數方法
Guava 對於浮點數計算的實現採用的完全是 JDK 中的方法, 但是在 Guava Math 中,
我們爲 [DoubleMath
] 添加了一些十分有用的方法.
Method 方法 | Description 描述 |
---|---|
[isMathematicalInteger(double) ] |
判斷這個數是一個有限數(非無窮)並且是一個精確的整數. |
[roundToInt(double, RoundingMode) ] |
圍繞這個特殊的數, 將其轉換成一個整形 int,如果溢出(超出int的範圍)則拋出異常 |
[roundToLong(double, RoundingMode) ] |
圍繞這個特殊的數, 將其轉換爲一個 long, 如果溢出, 則拋出異常. |
[roundToBigInteger(double, RoundingMode) ] |
將這個數轉換爲 BigInteger , 如果這個數是無限的, 則拋出異常. |
[log2(double, RoundingMode) ] |
取 2 的 log 對數, 並根據 RoundingMode 轉換爲 int; 比 JDK 中的 Math.log(double) 計算速度要快. |
後記:原文發佈在 Github 上,歡迎 Stars~