Math.abs(Integer.MIN_VALUE)问题分析

日常刷题中,然后有个地方是要求将当前数变成绝对值才可以使用;然后开开心心写了如下代码:

long a = Math.abs(Integer.MIN_VALUE);
System.out.println(a);

结果结果却让我大跌眼镜。但是一番分析下来倒是很有意思


点开源码(JDK1.8环境下)

这段话翻译过来就是,如果abs方法输入参数为正数,就返回那个值;如果未负数,就返回这个负数的对应绝对值;但是如果输入值为Integer.MIN_VALUE时;就返回输入值

这样看起来问题是解决了,但是身为一个合格的程序员,怎么可以不弄清楚原因呢。

1.原因分析

要讲清上面发生的原因,就必须把几个核心的问题都讲清楚;

1.1 原码

一开始人们是通过原码来表示整数,整数有正负之分,便通过符号位+二进制的方式表示。(最高位(最左边)取0表示正数,取1表示负数。然后加上对应的二进制。

+1 = 0000 0001
-1 = 1000 0001

1.2 反码

正数的反码是其本身
负数的反码是符号位不变 ,其他位都变为反

[+1] = [00000001]原 = [00000001]反
[-1] = [10000001]原 = [11111110]反

1.3 补码

正数的补码就是其本身
负数的补码是在其原码的基础上, 符号位不变, 其余各位取反, 最后+1. (即在反码的基础上+1)

[+1] = [00000001]原 = [00000001]反 = [00000001]补
[-1] = [10000001]原 = [11111110]反 = [11111111]补

那么为何要使用补码呢?

因为计算机中没有减法的概念,对应减法 a-b = a+(-b);

反码的方式
1 - 1 = 1 + (-1) = [00000001]原 + [10000001]原 = [10000010]原 = -2
1 - 1 = 1 + (-1) = [0000 0001]反 + [1111 1110]反 = [1111 1111]反 = [1000 0000]原 = -0
补码的方式
1 - 1 = 1 + (-1) = [0000 0001]补 +[1111 1111]补 = [0000 0000]补=0

所以这里如果1.8的jdk不限制,就容易导致结果错误;可以理解为

MIN_VALUE[反] = 0x80000000 = 10....0(中间29个0)= 1......1(中间30个1)
MIN_VALUE[补] = 0x80000000 = 10....0(中间29个0) = 1......1(中间30个1)+1 = 0......0(中间30个1)

所以 这里错误了;而且可以发现超出限制后,会形成一个循环

所以可以理解为为了防止这样的循环发生,JDK1.8出现这个保护的模式;而一切的发生源头就是补码导致

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章