赞
踩
最近在看算法书的时候发现一个非常有意思的现象,在java中输入:
System.out.println(Math.abs(-2147483648));
输出为:-2147483648
针对这个问题,我发现网上说的都不是很准确。
Math.abs(int x)的实现源码是这样的:
- public static int abs(int a) {
- return (a < 0) ? -a : a;
- }
首先要明确两个概念:(1)一个数在计算机中存储的是它的补码。
(2)Math.abs(a)中的-a对应计算机在内部的操作是:将a在计算机中的存储值(a的补码)所有位(32位)取反之后加1。
因此,-128在计算机中存储的是它的补码(它对应的正数的所有位取反+1):
128用二进制表示是:00000000 00000000 00000000 10000000
128所有位取反是:11111111 11111111 11111111 01111111
加1之后是:11111111 11111111 11111111 10000000(这个就是-128在计算机中存储的值(补码))
如果我们调用Math.abs(-128),机器会怎么做呢?
首先,取反:00000000 00000000 00000000 01111111
加一:00000000 00000000 00000000 10000000(128)
因此Math.abs(-128)的结果就是128.
同理,Math.abs(-2147483648)也是这样的操作:
-2147483648在计算机中存储的值是:10000000 00000000 00000000 00000000
Math.abs(-2147483648)中 -a操作,首先取反:01111111 11111111 11111111 11111111
然后加一:10000000 00000000 00000000 00000000
而上面这个数,计算机识别为-2147483648
补充知识:
对于正数来说,它的补码就是它本身。
对于负数来说,它的补码是它对应的正数的二进数所有位取反之后加一。
由负数的补码求原码也是相同的操作(所有位取反+1)即为该负数的绝对值
int是4个字节,32位,
10000000 00000000 00000000 00000000 是补码,第一位为符号位,1表示负数,所以
对剩下的位取反,结果为 1111111 11111111 11111111 11111111,加一后为10000000 00000000 00000000 00000000
所以原码指的是-2^31=-2147483648
int的取值范围为-2^31——2^31-1
在计算机中,负数的补码为:正值二进制取反+1。
注意: 1111111 11111111 11111111 11111111表示-1
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。