java 數(shù)學(xué)計算
java.lang.Math
庫提供了常用的數(shù)學(xué)計算工具
常量
final double E = 2.7182818284590452354; // 自然對數(shù)底數(shù)
final double PI = 3.14159265358979323846; // 圓周率
final double DEGREES_TO_RADIANS = 0.017453292519943295; // 角度轉(zhuǎn)弧度
final double RADIANS_TO_DEGREES = 57.29577951308232; // 弧度轉(zhuǎn)角度
取整
-
abs(x)
: 絕對值 -
floor(x)
: 向下取整 -
ceil(x)
: 向上取整 -
round(x)
: 四舍五入,如果有兩個(x.5
)怒见,返回較大的那個數(shù) -
rint(x)
: 最接近的整數(shù),如果有兩個(x.5
)谴咸,返回偶數(shù) -
floorDiv(x, y)
: 向下取整除法 -
floorMod(x, y)
: java 默認的取摸%
得到的結(jié)果和x
的符號相同收壕,floorMod
和y
的符號相同
double delta = 0.0000001;
assertEquals(Math.abs(-6), 6);
assertEquals(Math.floor(-6.2), -7, delta); // 向下取整
assertEquals(Math.floor(6.2), 6, delta);
assertEquals(Math.floor(6.8), 6, delta);
assertEquals(Math.ceil(-6.2), -6, delta); // 向上取整
assertEquals(Math.ceil(6.2), 7, delta);
assertEquals(Math.ceil(6.8), 7, delta);
assertEquals(Math.round(-6.2), -6, delta); // 四舍五入
assertEquals(Math.round(6.2), 6, delta);
assertEquals(Math.round(6.8), 7, delta);
assertEquals(Math.round(-6.5), -6, delta);
assertEquals(Math.round(6.5), 7, delta);
assertEquals(Math.rint(-6.2), -6, delta); // 最接近整數(shù)描馅,如果存在兩個竖伯,返回偶數(shù)
assertEquals(Math.rint(6.2), 6, delta);
assertEquals(Math.rint(6.8), 7, delta);
assertEquals(Math.rint(-6.5), -6, delta);
assertEquals(Math.rint(6.5), 6, delta);
assertEquals(Math.floorDiv(7, 3), 2);
assertEquals(Math.floorDiv(-7, 3), -3);
assertEquals(Math.floorMod(7, 3), 1);
assertEquals(Math.floorMod(-7, -3), -1);
assertEquals(Math.floorMod(-7, 3), 2);
assertEquals(-7 % -3, -1);
assertEquals(-7 % 3, -1);
三角函數(shù)
assertEquals(Math.sin(Math.PI / 2), 1.0, delta);
assertEquals(Math.cos(Math.PI), -1, delta);
assertEquals(Math.tan(Math.PI / 4), 1.0, delta);
assertEquals(Math.asin(1), Math.PI / 2, delta);
assertEquals(Math.acos(-1), Math.PI, delta);
assertEquals(Math.atan(1), Math.PI / 4, delta);
指數(shù)對數(shù)
-
pow(x, y)
:x^y
蜡镶,x
的y
次方 -
sqrt(x)
:√x
茫舶,x
的平方根 -
cbrt(x)
: 三次方根 -
hypot(x, y)
:√(x2 + y2)
-
exp(x)
:e ^ x
-
expm1(x)
:e ^ x - 1
-
log(x)
:ln(x)
-
log10
:lg(x)
-
log1p(x)
:ln(1+x)
assertEquals(Math.pow(3, 2), 9, delta);
assertEquals(Math.pow(2, 3), 8, delta);
assertEquals(Math.sqrt(4), 2, delta);
assertEquals(Math.cbrt(27), 3, delta);
assertEquals(Math.hypot(3, 4), 5, delta); // √(x2 + y2)
assertEquals(Math.exp(2.5), Math.pow(Math.E, 2.5), delta); // e ^ x
assertEquals(Math.expm1(2), Math.exp(2) - 1, delta); // e ^ x - 1
assertEquals(Math.log(Math.exp(1.5)), 1.5, delta); // ln(x)
assertEquals(Math.log10(1000), 3, delta); // lg(x)
assertEquals(Math.log1p(Math.E - 1), 1, delta); // ln(1 + x)
雙曲函數(shù)
-
sinh(x)
:(e ^ x - e ^ -x) / 2
-
cosh(x)
:(e ^ x + e ^ -x) / 2
-
tanh(x)
:sinh(x) / cosh(x)
assertEquals(Math.sinh(2), (Math.exp(2) - Math.exp(-2)) / 2, delta); // sinh(x) = (e ^ x - e ^ -x) / 2
assertEquals(Math.cosh(2), (Math.exp(2) + Math.exp(-2)) / 2, delta); // cosh(x) = (e ^ x + e ^ -x) / 2
assertEquals(Math.tanh(2), Math.sinh(2) / Math.cosh(2), delta); // tanh(x) = sinh(x) / cosh(x)
精確計算
普通的數(shù)值計算在溢出時是沒有感知的械巡,比如 Long.MAX_VALUE + 1
將得到結(jié)果 Long.MIN_VALUE
,為了解決這種不合理饶氏,Math
提供了一些輔助函數(shù)讥耗,在結(jié)果溢出時將拋出異常
-
addExact(x, y)
: 加法 -
multiplyExact(x, y)
: 乘法 -
decrementExact(x, y)
: 遞減 -
incrementExact(x, y)
: 遞增 -
negateExact(x, y)
: 相反數(shù) -
multiplyFull(x, y)
: 接受兩個int
返回一個long
,防止溢出 -
multiplyHigh(x, y)
: 返回兩個long
乘積的高64
位
assertEquals(Long.MAX_VALUE + 1, Long.MIN_VALUE); // 溢出
assertThrows(ArithmeticException.class, () -> Math.addExact(Long.MAX_VALUE, 1)); // 加法溢出拋異常
assertThrows(ArithmeticException.class, () -> Math.multiplyExact(Long.MAX_VALUE, 2)); // 乘法
assertThrows(ArithmeticException.class, () -> Math.decrementExact(Long.MIN_VALUE)); // 遞減
assertThrows(ArithmeticException.class, () -> Math.incrementExact(Long.MAX_VALUE)); // 遞增
assertThrows(ArithmeticException.class, () -> Math.negateExact(Long.MIN_VALUE)); // 相反數(shù)
assertEquals(Math.addExact(1, 2), 3);
assertEquals(Math.multiplyExact(2, 3), 6);
assertEquals(Math.incrementExact(6), 7);
assertEquals(Math.decrementExact(6), 5);
assertEquals(Math.negateExact(-6), 6);
assertEquals(Math.multiplyFull(1, 2), 2); // 接受兩個 int 返回一個 long疹启,防止溢出
assertEquals(Math.multiplyHigh(1, 2), 0); // 返回兩個 long 乘積的高 64 位
浮點數(shù)
任意兩個浮點數(shù)之間都有無數(shù)個浮點數(shù)古程,因此大部分浮點數(shù)是無法表示的,只能選取一個最接近的喊崖,java 提供了一些接口來獲取能表示的浮點數(shù)
System.out.println(Math.nextUp(1.1)); // 下一個浮點數(shù)
System.out.println(Math.nextDown(1.1)); // 上一個浮點數(shù)
System.out.println(Math.nextAfter(1.1, Double.POSITIVE_INFINITY)); // 下一個浮點數(shù)
System.out.println(Math.nextAfter(1.1, Double.NEGATIVE_INFINITY)); // 上一個浮點數(shù)
隨機數(shù)
math 庫隨機數(shù)
System.out.println(Math.random()); // 0 ~ 1 之間的隨機數(shù)
java.lang.Random
Random
類提供了更豐富的隨機方法挣磨,可以返回各種不同類型的隨機數(shù)
Random r = new Random();
System.out.println(r.nextInt());
System.out.println(r.nextLong());
System.out.println(r.nextFloat());
System.out.println(r.nextDouble());
Random
還提供了流式 api
Random r = new Random();
List<Integer> li = r.ints().limit(10).boxed().map((x) -> Math.abs(x % 100)).collect(Collectors.toList());
System.out.println(li);
java.util.Random
是線程安全的,但是荤懂,跨線程的同時使用 java.util.Random
實例可能會遇到爭用茁裙,從而導(dǎo)致性能下降。在多線程設(shè)計中考慮使用java.util.concurrent.ThreadLocalRandom
代替 java.util.Random
节仿,ThreadLocalRandom 和 Random 擁有一致的接口