Math.abs()求绝对值返回负值BUG分享

近期在推进代码质量的过程中,发现一个隐藏的知识点,就是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.abs(Integer.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热文精选