# Math 类中的 Java 精确算术运算支持

> 原文： [https://howtodoinjava.com/java8/java-8-exact-airthmetic-operations-supported-in-math-class/](https://howtodoinjava.com/java8/java-8-exact-airthmetic-operations-supported-in-math-class/)

Java 8 为 Java 开发人员带来了许多很棒的特性。 我已经在[比较器更改](//howtodoinjava.com/java8/using-comparator-becomes-easier-with-lambda-expressions-java-8/ "Using Comparator becomes easier with lambda expressions [Java 8]")，[流示例](//howtodoinjava.com/java8/java-8-tutorial-streams-by-examples/ "Java 8 Tutorial: Streams by Examples")，[内部与外部迭代](//howtodoinjava.com/java8/java-8-tutorial-internal-vs-external-iteration/ "Java 8 Tutorial: Internal vs. External Iteration")，[谓词](//howtodoinjava.com/2014/04/04/how-to-use-predicate-in-java-8/ "How to use Predicate in java 8")，[函数式接口](//howtodoinjava.com/java8/functional-interface-tutorial/ "Functional interface tutorial")，[默认方法](//howtodoinjava.com/java8/default-methods-in-java-8/ "Default methods in java 8")， [lambda 表达式](//howtodoinjava.com/java8/complete-lambda-expressions-tutorial-in-java/ "Complete lambda expressions tutorial")和[日期和时间 API 更改](//howtodoinjava.com/java8/date-and-time-api-changes-in-java-8-lambda/ "Date and Time API changes in Java 8 (Project Kenai)")。 以上所有更改都与 lambda 表达式有关，lambda 表达式是最受关注的获取者，也是改变游戏规则的人。

除了上述更改之外，我们还获得了非 lambda 表达式更改。 我已经在上一篇文章中讨论过[`String.join()`](//howtodoinjava.com/2014/05/02/java-8-string-join-csv-example/ "Java 8: String join (CSV) example")方法。 在本文中，我将讨论在`Math类中进行的**更改**，以支持精确的算术。

```java
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`方法将为您完成此工作，并且如果结果超出最大限制，则将引发异常。

```java

//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`

```java

//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。 如果事实为负数，结果对我来说是不可预测的。

```java
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 附带的精确数学执行上述取模操作。

```java
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`

如果将（位置+调整）计算为位置编号，则效果很好。 但是，如果时针逆时针移动，从而（位置+调整）变为负数，该怎么办。 让我们检查。

```java

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`。

```java

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()`方法将引发异常。

```java

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）的数字。

```java

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()`。

就是这样。 希望您喜欢阅读。 您的想法和评论总是受到欢迎。

 **学习愉快！**