1. Overview
1.概述
Dealing with numerical data often requires precision handling. One common scenario arises when we need to check whether a double is, in fact, a mathematical integer.
处理数字数据经常需要精确处理。当我们需要检查 double 事实上是否是数学整数时,就会出现一种常见的情况。
In this tutorial, we’ll explore the various techniques available to perform this check, ensuring accuracy and flexibility in our numeric evaluations.
在本教程中,我们将探讨执行这种检查的各种可用技术,以确保数字评估的准确性和灵活性。
2. Introduction to the Problem
2.问题介绍
First, as we know, a double is a floating-point data type that can represent fractional values and has a broader range than Java int or Integer. On the other hand, a mathematical integer is a whole number data type that cannot store fractional values.
首先,正如我们所知,double 是一种浮点数据类型,可以表示小数值,其范围比 Java int 或 Integer 更广。另一方面,数学整数是一种整数数据类型,不能存储小数值。
A double can be considered as representing a mathematical integer when the value after the decimal point is negligible or non-existent. This implies that the double holds a whole number without any fractional component. For example, 42.0D is actually an integer (42). However, 42.42D isn’t.
当小数点后的数值可忽略不计或不存在时,二进制可被视为代表一个数学整数。这意味着 该 double包含一个没有任何小数成分的整数。例如,42.0D 实际上是一个整数(42)。但是,42.42D 并非整数。
In this tutorial, we’ll learn several approaches to checking whether a double is a mathematical integer.
在本教程中,我们将学习几种检查 double 是否为数学整数的方法。
3. The Special Double Values: NaN and Infinity
3.特殊的双值:NaN 和 Infinity
Before we dive into checking if a double is an integer, let’s first look at a few special double values: Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY, and Double.NaN.
在深入检查 double 是否为整数之前,让我们先来看看几个特殊的 double 值:Double.POSITIVE_INFINITY、Double.NEGATIVE_INFINITY和Double.NaN.。
Double.NaN means the value is “not a number”. Thus, it’s not an integer either.
Double.NaN 表示值 “不是数字”。因此,它也不是一个整数。
On the other hand, both Double.POSITIVE_INFINITY and Double.NEGATIVE_INFINITY isn’t a concrete number in the traditional sense. They represent infinity, a special value that indicates a result of a mathematical operation that exceeds the maximum representable finite value for a double-precision floating-point number. Therefore, these two infinity values aren’t integers either.
另一方面,Double.POSITIVE_INFINITY和Double.NEGATIVE_INFINITY都不是传统意义上的具体数字。它们代表无穷大,这是一个特殊值,表示数学运算的结果超过了双精度浮点数可表示的最大有限值。因此, 这两个无穷大值也不是整数。
Further, the Double class provides the isNan() and isInfinite() methods to tell if a Double object is NaN or infinite. So, we can first perform these special values checks before we check if a double is an integer.
此外,Double 类提供了isNan()和isInfinite()方法,用于判断 Double 对象是 NaN 还是 infinite。因此,在检查 Double 是否为整数之前,我们可以首先执行这些特殊值检查。
For simplicity, let’s create a method to execute this task so that it can be reused in our code examples:
为了简单起见,让我们创建一个方法来执行这项任务,以便在我们的代码示例中重复使用:
boolean notNaNOrInfinity(double d) {
return !(Double.isNaN(d) || Double.isInfinite(d));
}
4. Casting the double to int
4.将 double 转换为 int
To determine whether a double is an integer, the most straightforward idea is probably first casting the double to an int and then compare the casted int to the original double. If their values are equal, the double is an integer.
要确定 double 是否是整数,最直接的方法可能是 首先将 double 转换为 int,然后将转换后的 int 与原始 double 进行比较。如果它们的值相等,则 double 就是整数。
Next, let’s implement and test this idea:
接下来,让我们来实施和测试这个想法:
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);
As the test shows, this approach does the job.
测试表明,这种方法确实有效。
However, as we know, double’s range is wider than int‘s in Java. So, let’s write a test to check what happens if the double exceeds the int range:
但是,我们知道,在 Java 中,double的范围比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
In this test, we assign 2.0D * Integer.MAX_VALUE to the double d3. Obviously, this value is a mathematical integer but out of Java’s integer range. So, it turns out that this approach won’t work if the given double is outside of the Java integer’s range.
在这个测试中,我们将 2.0D * Integer.MAX_VALUE 赋值给 double d3。很明显,这个值是一个数学整数,但超出了 Java 的整数范围。因此,事实证明,如果给定的 double 超出了 Java 整数的范围,这种方法将不起作用。
Moving forward, let’s explore alternative solutions that address scenarios where doubles surpass the range of integers.
展望未来,让我们探索其他解决方案,以解决 double 超过整数范围的情况。
5. Using the Modulo Operator ‘%‘
5.使用”%“调制操作符
We’ve mentioned that if a double is an integer, it doesn’t have a fractional part. Therefore, we can test if the double is divisible by 1. To do that, we can use the modulo operator:
我们已经提到,如果 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);
As the test shows, this approach works even if the double is out of the integer range.
正如测试所示,即使 double 不在整数范围内,这种方法也能奏效。
6. Rounding the double
6.双数四舍五入</em
The standard Math class provided a series of rounding methods:
- ceil() – Examples: ceil(42.0001) = 43; ceil(42.999) = 43
- floor() – Examples: floor(42.0001) = 42; floor(42.9999) = 42
- round() – Examples: round(42.4) = 42; round(42.5) = 43
- rint() – Examples: rint(42.4) = 42; rint(42.5) = 43
We won’t go into details of Math rounding methods in the list. All these methods share a common characteristic: they round the provided double to a close mathematical integer.
我们不会在列表中详细介绍 Math 四舍五入方法。所有这些方法都有一个共同特点:它们将提供的 double 四舍五入为一个接近的数学整数。
If a double represents a mathematical integer, after passing it to any rounding method in the list above, the result must be equal to the input double, for example:
例如,如果一个 double 表示一个数学整数,在将其传递给上述列表中的任何四舍五入方法后,结果必须等于输入的 double :
- ceil(42.0) = 42
- floor(42.0) = 42
- round(42.0) = 42
- rint(42.0) = 42
Therefore, we can use any rounding method to perform the check.
因此,我们可以使用任何四舍五入方法进行检查。
Next, let’s take the Math.floor() as an example to demonstrate how this is done:
接下来,让我们以 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);
As demonstrated by the test results, this solution remains effective even when the double exceeds the integer range.
测试结果表明,即使 double 超过整数范围,此解决方案仍然有效。
Of course, if we want, we can replace the floor() method with ceil(), round(), or rint().
当然,如果我们愿意,可以用 ceil(), round(), 或 rint() 替换 floor() 方法。
7. Using Guava
7.使用番石榴
Guava is a widely used open-source library of common utilities. Guava’s DoubleMath class provides the isMathematicalInteger() method. The method name implies that it’s exactly the solution we are looking for.
Guava是一个广泛使用的开源通用工具库。Guava的DoubleMath类提供了isMathematicalInteger()方法。该方法的名称意味着它正是我们正在寻找的解决方案。
To include Guava, we need to add its dependency to our pom.xml:
要包含 Guava,我们需要将其依赖关系添加到 pom.xml 中:
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>33.0.0-jre</version>
</dependency>
The latest version information can be found on Maven Repository.
最新版本信息可在 Maven Repository 上找到。
Next, let’s write a test to verify whether DoubleMath.isMathematicalInteger() works as expected:
接下来,让我们编写一个测试来验证 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);
As evidenced by the test results, the method consistently produces the expected result, no matter whether the input double falls within or outside the range of Java integers.
测试结果表明,无论输入的 double 是在 Java 整数范围之内还是之外,该方法都能始终如一地产生预期结果。
Sharp eyes might have noticed we didn’t call notNaNOrInfinity() in the test above for NaN and infinity check. This is because the DoubleMath.isMathematicalInteger() method handles NaN and infinity too:
眼尖的人可能已经注意到,我们在上面的测试中没有调用 notNaNOrInfinity() 来检查 NaN 和无穷大。这是因为DoubleMath.isMathematicalInteger()方法也能处理NaN和无穷大:。
boolean isInfinityInt = DoubleMath.isMathematicalInteger(Double.POSITIVE_INFINITY);
assertFalse(isInfinityInt);
boolean isNanInt = DoubleMath.isMathematicalInteger(Double.NaN);
assertFalse(isNanInt);
8. Conclusion
8.结论
In this article, we first discussed what “a double represents a mathematical integer” means. Then, we’ve explored different ways to check whether a double indeed qualifies as a mathematical integer.
在本文中,我们首先讨论了 “一个 double 表示一个数学整数 “的含义。然后,我们探讨了检查 double 是否确实符合数学整数条件的不同方法。
While the straightforward casting of a double to an int (i.e., theDouble == (int) theDouble) may seem intuitive, its limitation lies in its inability to handle cases where theDouble falls beyond the range of Java integers.
将 double 直接转换为 int(即 theDouble == (int) theDouble)看似直观,但其局限性在于无法处理 theDouble 超出 Java 整数范围的情况。
To address this limitation, we looked at moduli and rounding approaches, which can correctly handle doubles whose values extend beyond the integer range. Furthermore, we demonstrated the DoubleMath.isMathematicalInteger() method from Guava as an additional, robust solution to our problem.
为了解决这一限制,我们研究了模数和四舍五入方法,这些方法可以正确处理数值超出整数范围的 doubles 。此外,我们还演示了 Guava 中的 DoubleMath.isMathematicalInteger() 方法,它是解决我们问题的另一种稳健的方法。
As always, the complete source code for the examples is available over on GitHub.
与往常一样,这些示例的完整源代码可在 GitHub 上获取。