1. 概述
在这个教程中,我们将探讨如何计算两个给定整数之间的绝对差。
2. 使用 Math.abs()
方法
问题很简单。让我们通过几个例子快速理解:
num1=3, num2=4
:absDiff=1
num1=3, num2=-4
:absDiff=7
num1=-3, num2=-4
:absDiff=1
从上面的例子可以看出,*给定两个整数 num1 和 num2,结果是 (num1 - num2) 的绝对值。* 此外,Java 标准库提供了 Math.abs()
方法来返回一个数的绝对值。因此,我们可以轻松地将计算转换为 Java 代码:
public int absDiff(int num1, int num2) {
return Math.abs(num1 - num2);
}
如我们所见,absDiff()
方法返回结果,并打印出来。
为了简化,让我们使用单元测试断言来验证方法是否按预期工作:
@Test
public void testAbsDiff() {
assertEquals(1, absDiff(3, 4));
assertEquals(7, absDiff(3, -4));
assertEquals(1, absDiff(-3, -4));
}
当我们运行测试时,它会通过。所以,我们已经解决了这个问题。然而,这个实现隐藏了一个潜在问题。接下来,让我们解决它。
3. 浮动/下溢问题
我们知道 Java 的 int
是一个有符号的 32 位整数。换句话说,Java 整数的范围是 -2147483648
到 2147483647
。
现在,让我们回顾一下我们的实现。我们有计算:num1 - num2
。因此,当我们将 Integer.MAX_VALUE
和 -200
传递给 absDiff()
方法时,结果可能会超过 Integer.MAX_VALUE
。接下来,让我们用这两个数字调用该方法看看会发生什么。
首先,手动计算一下预期结果:
Result = Integer.MAX_VALUE - (-200)
= 2147483647 + 200
= 2147483847
然而,如果我们调用 absDiff()
方法,不会出现异常,而是看到输出:
Absolute diff: 2147483449
显然,结果不正确。这是因为发生了整数溢出(overflow)。 当然,计算结果也可能会小于 Integer.MIN_VALUE
,例如 absDiff(Integer.MIN_VALUE, 200)
。在这种情况下,我们称之为下溢。
接下来,我们将探讨如何解决溢出/下溢问题。
4. 使用不同的数据类型
在 Java 中,有一些范围大于 int
的数字类型,如 long
或 BigInteger
。为了避免溢出/下溢问题,我们可以在执行计算之前将 int
参数转换为这些类型之一。以 long
为例,我们在新方法中实现逻辑:
public int absDiff(int num1, int num2) {
long diff = Math.subtractExact(num1, num2);
return (int) Math.abs(diff);
}
现在,让我们测试当我们将 Integer.MAX_VALUE
和 -200
传递给它时,它是否能给出预期的结果:
long diff = absDiffAsLong(Integer.MAX_VALUE, -200);
assertEquals(Integer.MAX_VALUE + 200L, diff);
如果运行测试,它会通过。因此,这种方法解决了溢出/下溢问题。但是值得注意的是,返回类型是 long
而不是 int
。
如果调用者期望结果为 long
,那没关系。否则,如果需要 int
,我们必须将 long
值转换为 int
。这很不方便。而且,如果我们错误地进行 long
到 int
的转换,也可能发生溢出/下溢问题。
接下来,我们将看看是否可以保持结果为 int
并避免溢出/下溢问题。
5. 当溢出/下溢发生时抛出异常
假设我们的程序需要整数形式的绝对差结果。那么,方法的理想行为是返回一个 int
,并在发生溢出/下溢时抛出异常。
然而,正如我们之前看到的,Java 在普通的 (num1 - num2)
计算过程中不会在溢出时抛出异常。这使得当我们发现程序没有产生预期结果时,很难找到真正的原因。
自 Java 8 开始,Java 的 Math 提供了新的 精确运算方法。这些方法在溢出/下溢发生时抛出 ArithmeticException
。因此,让我们将 absDiff()
方法中的 (num1 - num2)
替换为 subtractExact()
:
public int absDiff(int num1, int num2) {
long diff = Math.subtractExact(num1, num2);
return (int) Math.abs(diff);
}
最后,以下测试表明 absDiff2()
如预期工作:
int diff1 = absDiff2(100, -200);
assertEquals(300, diff1);
int diff2 = absDiff2(100, 200);
assertEquals(100, diff2);
//overflow -> exception
assertThrows(ArithmeticException.class, () -> absDiff2(Integer.MAX_VALUE, -200));
6. 总结
在这篇文章中,我们探讨了计算两个整数之间的绝对差。此外,我们讨论了溢出/下溢问题。
如往常一样,文章中展示的所有代码片段可在 GitHub 上获取。