由 Math.abs 谈负数转换与绝对值运算

全文转载自我的博客,更好的阅读体验和更多内容欢迎移步SSpiritsの秘密基地

本文通过分析一个 Java 中 Math.abs() 误用引发的 bug 介绍了计算机中数的储存、负数转换与绝对值运算

背景

最近遇到了一个奇妙深刻的 bug:我们的系统中使用了一个 int 型的变量来计数,这个计数器变量的绝对值取模作为某个 list 的 index,但是今天出现了异常 IndexOutOfBoundsException

// 满足某些条件计数器自增
int count = 0;
count++int index = Math.abs(count) % list.size();
// java.lang.IndexOutOfBoundsException: Index -2147483648 out of bounds for length 1
list.get(index);

Math.abs 遇上 Integer.MIN_VALUE

我们知道 int 是用 32 位二进制储存的,其中最高位是符号位。上述代码不断自增 count 变量最终会使其超过上限从而反转成负数(Integer.MAX_VALUE + 1 == Integer.MIN_VALUE 会返回 true) 我们预料到了这种情况发生所以使用 Math.abs(count) 来确保取模的结果为正数,但是结果事与愿违

我们查看报错信息发现 -2147483648 正好是 Integer.MIN_VALUE,所以我们先试一下 Math.abs(Integer.MIN_VALUE) 结果居然是 -2147483648,这显然不符合我们的预期,让我们先来看一下 Math.abs() 的实现:

    /**
     * Returns the absolute value of an {@code int} value.
     * If the argument is not negative, the argument is returned.
     * If the argument is negative, the negation of the argument is returned.
     *
     * 

Note that if the argument is equal to the value of * {@link Integer#MIN_VALUE}, the most negative representable * {@code int} value, the result is that same value, which is * negative. * * @param a the argument whose absolute value is to be determined * @return the absolute value of the argument. */ @HotSpotIntrinsicCandidate public static int abs(int a) { return (a < 0) ? -a : a; }

注释中说明了如果 a 是 Integer.MIN_VALUE 那么返回值也是负数。到这里就破案了,只要把 Math.abs(count) % list.size() 改为 (count % lis

你可能感兴趣的:(Java,算法,安全相关,java,算法,math)