为什么Java中int型数据取值范围是[-2^{31}, 2^{31}-1]

一、整数在计算机中的存储形式

数字计算机中的存储形式
− 2 31 -2^{31} 2311000 0000 0000 0000 0000 0000 0000 0000
− 2 31 + 1 -2^{31} + 1 231+11000 0000 0000 0000 0000 0000 0000 0001
− 2 31 + 2 -2^{31} + 2 231+21000 0000 0000 0000 0000 0000 0000 0010
− 2 31 + 3 -2^{31} + 3 231+31000 0000 0000 0000 0000 0000 0000 0011
− 2 31 + 4 -2^{31} + 4 231+41000 0000 0000 0000 0000 0000 0000 0100
− 2 31 + 5 -2^{31} + 5 231+51000 0000 0000 0000 0000 0000 0000 0101
− 2 31 + 6 -2^{31} + 6 231+61000 0000 0000 0000 0000 0000 0000 0110
− 2 31 + 7 -2^{31} + 7 231+71000 0000 0000 0000 0000 0000 0000 0111
− 2 31 + 8 -2^{31} + 8 231+81000 0000 0000 0000 0000 0000 0000 1000
− 8 -8 81111 1111 1111 1111 1111 1111 1111 1000
− 7 -7 71111 1111 1111 1111 1111 1111 1111 1001
− 6 -6 61111 1111 1111 1111 1111 1111 1111 1010
− 5 -5 51111 1111 1111 1111 1111 1111 1111 1011
− 4 -4 41111 1111 1111 1111 1111 1111 1111 1100
− 3 -3 31111 1111 1111 1111 1111 1111 1111 1101
− 2 -2 21111 1111 1111 1111 1111 1111 1111 1110
− 1 -1 11111 1111 1111 1111 1111 1111 1111 1111
0 0 00000 0000 0000 0000 0000 0000 0000 0000
1 1 10000 0000 0000 0000 0000 0000 0000 0001
2 2 20000 0000 0000 0000 0000 0000 0000 0010
3 3 30000 0000 0000 0000 0000 0000 0000 0011
4 4 40000 0000 0000 0000 0000 0000 0000 0100
5 5 50000 0000 0000 0000 0000 0000 0000 0101
6 6 60000 0000 0000 0000 0000 0000 0000 0110
7 7 70000 0000 0000 0000 0000 0000 0000 0111
8 8 80000 0000 0000 0000 0000 0000 0000 1000
2 31 − 8 2^{31} - 8 23180111 1111 1111 1111 1111 1111 1111 1000
2 31 − 7 2^{31} - 7 23170111 1111 1111 1111 1111 1111 1111 1001
2 31 − 6 2^{31} - 6 23160111 1111 1111 1111 1111 1111 1111 1010
2 31 − 5 2^{31} - 5 23150111 1111 1111 1111 1111 1111 1111 1011
2 31 − 4 2^{31} - 4 23140111 1111 1111 1111 1111 1111 1111 1100
2 31 − 3 2^{31} - 3 23130111 1111 1111 1111 1111 1111 1111 1101
2 31 − 2 2^{31} - 2 23120111 1111 1111 1111 1111 1111 1111 1110
2 31 − 1 2^{31} - 1 23110111 1111 1111 1111 1111 1111 1111 1111

二、计算机存储数字的原理

2.1.原码

int型数据在计算机中以二进制存储,一个int型数据占4个字节,一个字节占8位,一共32位。
(1)第一位是标志位,标志位为0表示正数,标志位为1表示负数。
(2)剩余的31位是用来表示数字部分的

2.2.补码

在计算机中,数字以补码存储。正数的补码是其本身,负数的补码是除标志位外,其他位按位取反再加一。

2.3.补码的特性

1、一个负整数(或原码)与其补数(或补码)相加,和为模。
2、对一个整数的补码再求补码,等于该整数自身。
3、补码的正零与负零表示方法相同。


三、两个例子理解补码的计算方式

3.1、第一个例子:7的存储形式

3.1.1.原码

(1)7是正数,所以标志位为0
(2)剩余的31位表示数字部分:000 0000 0000 0000 0000 0000 0000 0111
所以7的原码是:
0000 0000 0000 0000 0000 0000 0000 0111

3.1.2.补码

正数的补码与原码一样,所以7在计算机中的存储形式为:
0000 0000 0000 0000 0000 0000 0000 0111

3.2、第二个例子:-7的存储形式

3.2.1.原码

(1)-7是负数,所以标志位为1
(2)剩余的31位表示数字部分:000 0000 0000 0000 0000 0000 0000 0111
所以-7的原码是:
1000 0000 0000 0000 0000 0000 0000 0111

3.2.2.补码

负数的补码是除标志位外,其他位按位取反再加一。所以-7在计算机中的存储形式为:
1111 1111 1111 1111 1111 1111 1111 1001


四、为什么int型数据取值范围是 [ − 2 31 , 2 31 − 1 ] [-2^{31}, 2^{31}-1] [231,2311]

由原理可知,计算机存储数字时,第一位是标志位,只有31位用来存储数字的值。所以最大表示的正数为0111 1111 1111 1111 1111 1111 1111 1111,即: 2 31 − 1 2^{31}-1 2311
对于负数,当存储数字的31位均为1时,值为 2 31 − 1 2^{31}-1 2311,加上标志位1,此时的负数原码为:
1111 1111 1111 1111 1111 1111 1111 1111
对应的补码为:
1000 0000 0000 0000 0000 0000 0000 0001
用类似的表示方法可以表示出 [ − 2 31 + 1 , 2 31 − 1 ] [-2^{31}+1, 2^{31}-1] [231+1,2311]中的数,但是如果这么计算的话,1000 0000 0000 0000 0000 0000 0000 0000 这个数字就被浪费了。对于计算机宝贵的内存,浪费是绝对不允许的,所以1000 0000 0000 0000 0000 0000 0000 0000这个数字就被规定为表示 − 2 31 -2^{31} 231。所以int型数据取值范围是 [ − 2 31 , 2 31 − 1 ] [-2^{31}, 2^{31}-1] [231,2311]


五、为什么要用补码

5.1.类比:时钟使用补码计算加减

例如:时钟的计量范围是0~23,所以时间的模等于24。假设当前时针指向17点,而准确时间是9点,调整时间可有以下两种方法:
1.倒拨8小时,即:17 - 8 = 9;
2.顺拨16小时:17 + 16 = 33 ; 33 % 24 = 9
此例中, 16 就是 -8 在 24 进制中的补码表示。用 16 表示 -8 的好处是将减法转为了加法。

5.2.计算机使用补码计算加减

如果正数和负数都用原码表示,计算机计算加减法需要做不同的处理。而如果使用补码表示,计算机计算加减法时统一使用加法计算即可,减轻了计算机的负担。

5.2.1.第一个例子:计算 9 + 5

9 的补码表示为:
0000 0000 0000 0000 0000 0000 0000 1001
5 的补码表示为:
0000 0000 0000 0000 0000 0000 0000 0101
两个补码相加,并去掉32位以外的数(本例结果没有32位以外的数):
0000 0000 0000 0000 0000 0000 0000 1110
即得到了结果 14

5.2.2.第二个例子:计算 9 - 5

9 的补码表示为:
0000 0000 0000 0000 0000 0000 0000 1001
-5 的补码表示为:
1111 1111 1111 1111 1111 1111 1111 1011
两个补码相加,并去掉32位以外的数:
0000 0000 0000 0000 0000 0000 0000 0100
即得到了结果 4

5.2.3.第三个例子:计算 − 2 31 + 1 -2^{31}+1 231+1

上文说道,为了不浪费内存,1000 0000 0000 0000 0000 0000 0000 0000这个数字被规定为表示 − 2 31 -2^{31} 231,事实上这个数字表示 − 2 31 -2^{31} 231并不是凭空规定的,它也符合补码的加减规则。
− 2 31 -2^{31} 231 的补码表示为:
1000 0000 0000 0000 0000 0000 0000 0000
1 的补码表示为:
0000 0000 0000 0000 0000 0000 0000 0001
两个补码相加,并去掉32位以外的数(本例结果没有32位以外的数):
1000 0000 0000 0000 0000 0000 0000 0001
即得到了结果 − 2 31 + 1 -2^{31}+1 231+1


六、拓展

由原理可推导出:
Java中short型整数占16位,取值范围: [ − 2 15 , 2 15 − 1 ] [-2^{15}, 2^{15}-1] [215,2151]
long型整数占64位,取值范围: [ − 2 63 , 2 63 − 1 ] [-2^{63}, 2^{63}-1] [263,2631]


附一:位、字节、字符的区别

  • 位(bit):计算机内部,数据储存的最小单位。如:00110011 是一个八位二进制数
  • 字节(byte):计算机中数据处理的基本单位。通常用大写的 B 表示,1 byte = 8 bit
  • 字符:计算机中使用的字母、数字、字、符号。

在 ASCII 编码中:
1 个英文字母占 1 个字节
1 个汉字占 2 个字节
1 个 ASCII 码占 1 个字节

在 UTF-8 编码中:
1 个英文字符、英文标点占 1 个字节
1 个中文字符、中文标点占 3 个字节

在 Unicode 编码中:
1 个英文字符、英文标点占 2 个字节
1 个中文字符、中文标点占 2 个字节

附二:Java 中八种基本数据类型占用空间

  • boolean:1 字节
  • byte:1 字节
  • short:2 字节
  • char:2 字节
  • int:4 字节
  • float:4 字节
  • long:8 字节
  • double:8 字节

注:

  • 不带后缀的整数默认为 int,不带后缀的小数默认为 double
  • 超出 int 取值范围的整数必须添加后缀 L或者l,表示 long 类型。建议使用L,因为l容易与数字 1 混淆
  • 带有Ff后缀的数都属于 float 类型,带有Dd后缀的数都视为 double 类型
  • 编译器会在编译期检查八种基本类型的取值范围,如果超出了范围会报错
  • int 值可以赋值给所有数值类型;
  • long 值可以赋值给 long、float、double类型,为什么 long 值占 8 个字节可以赋值给只占 4 个字节的 float 呢?这是因为赋值时会自动舍弃精度并转换为科学计数法。如:Long.MAX_VALUE: 9223372036854775807,赋值给 float,变为:9.223372E18
  • float 值可以赋值给 float、double 类型
  • double 值只能赋值给 double 类型

参考文章

1.补码_百度百科:https://baike.baidu.com/item/%E8%A1%A5%E7%A0%81

2.Java中八种基本数据类型占用字节空间总结

3.位、字节、字符的区别

评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值