近期在推进代码质量的过程中,发现一个隐藏的知识点,就是Math.abs()求一个int数据的绝对值的时候会出现返回结果为负值的BUG

code

public static String getPassword() {
    Random rd = new Random(); // 创建随机对象
    String n = ""; // 保存随机数
    int rdGet; // 取得随机数
    do {
        if (rd.nextInt() % 2 == 1) {
            rdGet = Math.abs(rd.nextInt()) % 10 + 48; // 产生48到57的随机数(0-9的键位值)
        } else {
            rdGet = Math.abs(rd.nextInt()) % 26 + 97; // 产生97到122的随机数(a-z的键位值)
        }
        char num1 = (char) rdGet; // int转换char
        String dd = Character.toString(num1);
        n += dd;
    } while (n.length() < 8);// 设定长度,此处假定长度小于8
    return n;
}

message

This code generates a random signed integer and then computes the absolute value of that random integer. If the number returned by the random number generator is Integer.MIN_VALUE, then the result will be negative as well (since Math.abs(Integer.MIN_VALUE) == Integer.MIN_VALUE). (Same problem arises for long values as well).

消息

错误地计算有符号随机整数的绝对值
此代码生成一个随机的有符号整数然后计算该随机整数的绝对值 如果随机数生成器返回的数字为Integer.MIN_VALUE则结果也将为负因为Math.absInteger.MIN_VALUE== Integer.MIN_VALUE)。 长值也会出现相同的问题)。

测试 Demo

刚看到这个错误一时间让我有些不知所措,怎么就是 BUG 了。结果我上手写了一个Demo进行测试。

public static void main(String[] args) {
    int min = Integer.MIN_VALUE;
    int max = Integer.MAX_VALUE;
    output("最小值:" + min);
    output("最大值:" + max);
    int abs = Math.abs(min);
    output("绝对值:" + abs);

    Integer integer = new Integer(-min);
    output("负最小值:" + integer);
}

控制台输出

INFO-> 当前用户:fv,IP:10.60.192.21,工作目录:/Users/fv/Documents/workspace/fun/,系统编码格式:UTF-8,系统Mac OS X版本:10.15.7
INFO-> 最小值:-2147483648
INFO-> 最大值:2147483647
INFO-> 绝对值:-2147483648
INFO-> 负最小值:-2147483648

Process finished with exit code 0

诚不欺我,为了了解其中奥妙,我查到了一篇文章,算是解惑了。

答疑解惑

首先我们看Math.abs()的源码:

public static int abs(int a) {
    return (a < 0) ? -a : a;
}

** 按照 JLS 的第 15.15.4 中,-x 等于 (~x)+1,其中~是位运算符。 **

也就是说int类型的最小值是-2147483648,首先进行了符号位的运算,把-2147483648(也就是符号1,后面 31 个1)转变成2147483647(符号位0,后面 31 个1),这里并不是之前数学上直接负负得正得到2147483648,显然这已经超过了int类型最大值。然后把得到的2147483647(这里已经是int类型的最大值),然后进行+1操作,得到了-2147483648(符号位1,后面 31 个1)。


公众号FunTester,原创分享爱好者,腾讯云、开源中国和掘金社区首页推荐,知乎八级强者,欢迎关注、交流, 禁止第三方擅自转载。

FunTester 热文精选


↙↙↙阅读原文可查看相关链接,并与作者交流