Math 类中的 Java 精确算术运算支持
Math 类中的 Java 精确算术运算支持
Java 8 为 Java 开发人员带来了许多很棒的特性。 我已经在比较器更改,流示例,内部与外部迭代,谓词,函数式接口,默认方法, lambda 表达式和日期和时间 API 更改。 以上所有更改都与 lambda 表达式有关,lambda 表达式是最受关注的获取者,也是改变游戏规则的人。
除了上述更改之外,我们还获得了非 lambda 表达式更改。 我已经在上一篇文章中讨论过String.join()
方法。 在本文中,我将讨论在`Math类中进行的更改,以支持精确的算术。
Sections in this post:
1) (add|substract|multiply|increment|decrement|negate)Exact methods
2) floorMod and floorDiv methods
3) toIntExact method
4) nextDown method
让我们一一讨论。
1)加减乘除和求反的精确方法
Math
类提供了这些新方法,每次操作结果溢出到最大限制时,这些方法都会引发java.lang.ArithmeticException
异常。 以上所有方法都将参数作为int
或long
原始类型。
例如考虑乘以100000 * 100000
。通常,这样做会“无声地”给您带来错误的回报,并且在应用程序运行时,您有责任每次检查最大限制以避免错误的计算。
在 Java 8 中,multiPlyExact
方法将为您完成此工作,并且如果结果超出最大限制,则将引发异常。
//Normal multiplication
System.out.println( 100000 * 100000 );
//Using multiPlyExact
System.out.println( Math.multiplyExact( 100000 , 100000 ));
Output:
1410065408 //Incorrect result
Exception in thread "main" java.lang.ArithmeticException: integer overflow
at java.lang.Math.multiplyExact(Math.java:867)
at java8features.MathematicalFuctions.main(MathematicalFuctions.java:8)
其他操作也会发生相同的情况。 例如添加操作与addExact
//Normal add operation
System.out.println( Integer.MAX_VALUE + Integer.MAX_VALUE );
//Using addExact
System.out.println( Math.addExact( Integer.MAX_VALUE , Integer.MAX_VALUE ));
Output:
-2 //incorrect result
Exception in thread "main" java.lang.ArithmeticException: integer overflow
at java.lang.Math.addExact(Math.java:790)
at java8features.MathematicalFuctions.main(MathematicalFuctions.java:11)
2)floorMod
和floorDiv
方法
Java 8 已经解决了很长的整数余数问题。 大家都知道n % 2
是
i) 0:如果数字是偶数
ii) 1:如果是奇数
如果数字为负怎么办。 上面的表达式可以/不能返回 -1。 如果事实为负数,结果对我来说是不可预测的。
System.out.println( 10 % 2 );
System.out.println( 11 % 2 );
System.out.println( -15 % 2 );
System.out.println( -16 % 2 );
Output:
0
1
-1
0
现在,使用 Java 8 附带的精确数学执行上述取模操作。
System.out.println( Math.floorMod(10 , 2) );
System.out.println( Math.floorMod(11 , 2) );
System.out.println( Math.floorMod(-15 , 2) );
System.out.println( Math.floorMod(-16 , 2) );
Output:
0
1
1
0
类似地,另一个问题可能是获取时钟的时针位置。 假设当前时间是 10 点。 您已经调整了 n 小时,现在想获得排名。 公式很简单:
Current Position = (position + adjustment) % 12
如果将(位置+调整)计算为位置编号,则效果很好。 但是,如果时针逆时针移动,从而(位置+调整)变为负数,该怎么办。 让我们检查。
System.out.println( (10+3) % 12 );
System.out.println( (5+6) % 12 );
System.out.println( (10-27) % 12 );
Output:
1
11
-5 //This is incorrect
现在,使用精确的浮点方法floorMod
。
System.out.println( Math.floorMod(10+3 , 12) );
System.out.println( Math.floorMod(5+6 , 12) );
System.out.println( Math.floorMod(10-27 , 12) );
Output:
1
11
7 //This is correct
在floorDiv()
方法中也进行了类似的更改。
3)toIntExact
方法
当您尝试为int
类型变量分配一个long
值时,此方法很方便。 虽然这种情况并非易事,但在极少数情况下可能会需要。 如果long
值大于最大int
值,则正常的long
到int
转换会导致数据错误。 如果发生类似这种情况,toIntExact()
方法将引发异常。
System.out.println( Long.MAX_VALUE );
System.out.println( (int)Long.MAX_VALUE );
System.out.println( Math.toIntExact(10_00_00_000) );
System.out.println( Math.toIntExact(Long.MAX_VALUE) );
Output:
9223372036854775807
-1
100000000
Exception in thread "main" java.lang.ArithmeticException: integer overflow
at java.lang.Math.toIntExact(Math.java:1011)
at java8features.MathematicalFuctions.main(MathematicalFuctions.java:46)
4)nextDown
方法
这也是 Java 8 套件中的一个明显新增特性。 当您需要返回小于 n 的数字时,这非常有用。 您计算的返回数字恰好是 n。 然后,您可以使用此方法查找最接近 n(但仍小于 n)的数字。
System.out.println( Math.nextDown(100) );
System.out.println( Math.nextDown(100.365) );
Output:
99.99999
100.36499999999998
请注意,自 Java 6 起,Math.nextUp()
已经存在。在 Java 8 中仅添加了Math.nextDown()
。
就是这样。 希望您喜欢阅读。 您的想法和评论总是受到欢迎。