您的位置:首页 > 其它

关于补零扩展与补符号位扩展

2017-09-11 12:54 627 查看
众所周知,每种基本数据类型都有一个固定的位数,比如byte占8位,short占16位,int占32位等。正因如此,当把一个低精度的数据类型转成一个高精度的数据类型时,必然会涉及到如何扩展位数的问题。这里有两种解决方案:

(1)补零扩展:填充一定位数的0。

(2)补符号位扩展:填充一定位数的符号位(非负数填充0,负数填充1)。

对于无符号类型(相当于都是非负数)与有符号类型中的非负数部分,这两种方法没有区别,都是填充0;对于有符号类型中的负数部分,这两种方法就会产生差异了,补零扩展会填充0,而补符号位扩展会填充1。下面将byte类型的-127转为int类型为例,探讨一下这两种方法的区别。

首先必须明确一些知识点:

计算机是用补码来存储数字的;

正数的补码等于原码;

负数的补码等于反码+1;

一个数的补码的补码等于原码。

127原码1111 1111,反码1000 0000,补码1000 0001。计算机存储的是1000 0001,用十六进制表示为0x81。

当使用补零扩展时,结果为:

0000 0000 0000 0000 0000 0000 1000 0001

用十六进制表示为0x81。为了计算十进制值,计算它的补码,结果为:

0000 0000 0000 0000 0000 0000 1000 0001

将这个二进制数转成十进制的结果是129。

当使用补符号位扩展时,结果为:

1111 1111 1111 1111 1111 1111 1000 0001

用十六进制表示为0xFFFFFF81。为了计算十进制值,计算它的补码,结果为:

1000 0000 0000 0000 0000 0000 0111 1111

将这个二进制数转成十进制的结果是-127。

由此可以得出结论:

(1)使用补零扩展能够保证二进制存储的一致性,但不能保证十进制值不变。

(2)使用补符号位扩展能够保证十进制值不变,但不能保证二进制存储的一致性。

下面以Java为例进行验证(Java中没有无符号类型,只有有符号类型):

public static void main(String[] args){
byte b = -127;
System.out.println(Integer.toBinaryString((int)b));
System.out.println(Integer.toBinaryString((int)(b & 0xFF)));
}

输出:
11111111111111111111111110000001
10000001


由此又可以得出结论:

(1)对于有符号类型,Java使用的是补符号位扩展,这样能保证十进制的值不变;

(2)如果想要用补零扩展来确保二进制的内容不变,可以通过& 0xFF(不一定是8位,根据待转换的数据位数而定)实现。本质是将前面补上的1都通过与运算改成了0。

关于b & 0xFF为什么会导致结果改变的问题,个人认为应当是在进行这个运算之前,b已经进行了补符号位扩展,变成了32位(否则 b & 0xFF → 1000 0001 & 1111 1111 == 1000 0001 == b)。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  数据 扩展