计算机中的数字均以补码的形式表示
原码
原码表示法在数值前面增加了以为符号位(最高位为符号位):
正数该位为0,负数该位为1(0有两种表示:+0和-0),其余位表示数值的大小。
例如,我们用8位二进制表示一个数,+11的原码为00001011,-11的原码就是10001011
补码
正数的补码与原码相同
负数的补码对其原码逐位取反,但符号位除外;然后整个数加1。
-7的原码(10000111)→按位取反(11111000)(负数符号位不变)→加1(11111001)
正数的补码转换为负数的补码
正数补码与原码,反码都相同,只要把正数补码的最高位设为1,其他位求反,然后+1
12345的补码0011000000111001
-12345的补码1100111111000111
有符号数转换为无符号数(强制类型转换):
不改变参数的位的表示,只是改变了如何讲这些位解释为一个数字
有符号-1234561100111111000111
无符号 531911100111111000111
C语言中的有符号与无符号数
C语言支持所有整型数据类型的有符号与无符号运算,大多数数字都被认为是有符号的.
例如,当声明一个像12345或者0x1A2B这样的常量时,这个值就被认为是有符号的
C语言中无符号和有符号的转换(强制类型转换),隐式类型转换 int tx,ty; unsigned ux,uy;tx = ux, uy = ty;
底层的位表示保持不变
C语言对同时包含有符号与无符号数表达式的处理方式
C语言会隐式的的将有符号参数强制类型转换为无符号数,并假设这两个数都是非负的
例如: -5 + 3
1011 + 0011 = 1110
从一个数据大小到另一个数据大小的转换,
以及无符号和有符号数字之间的转换的相对顺序能够影响一个程序的行为
C语言标准要求 short转换成unsigned既(unsigned)short等价于(unsigned)(int)short
扩展一个数字的位的表示
从一个较小的数据类型转换到一个较大的数据类型:
无符号数:零扩展 即在位模式的开头添加0
二进制补码:符号扩展 在表示中添加最高有效位的值
截断数字
将一个w位的数截断为一个k位的数时,我们会丢弃w-k位.(可能会产生溢出)
32位int x = 53191(x 0000 0000 0000 0000 1100 1111 1100 0111);
short sx = (short)x (sx1100 1111 1100 0111 -12345的补码);
对于一个无符号数字x,截断它到k位的结果
x mod 2的k次方
例如 无符号15截断1位 1111 截断 1位 等于111 (7)
补码 -1截断1位 1111 截断 1位 等于111(-1)
关于有符号与无符号的建议
绝不使用无符号数
java只支持有符号整数,并且要求用补码来实现,正常的右移>>被定为算数右移(前面补0).
特殊的运算符>>>被定为逻辑右移(前面补最高位的副本)
无符号(无符号)加法
截取掉高位,留下低w位表示的值
溢出是指一个算数运算的整数结果不能放到数据类型的限制中去
例如:四位数字表示,x=9,y=12;的位分别表示[1001],[1100]他们的和位21,五位的表示为[10101]
无符号加法运算等价于计算模2的w位次方的和, 上例中 21 mod 2的4次方
判断发生了溢出
int uadd_ok(unsigned x, unsigned y){ int sum = x + y; return sam >= 0; }
有符号无符号乘法
截取掉高位,留下低w位表示的值