补码与符号位取反

博客通过 C 语言小例子探讨补码与符号位取反。介绍有符号整数的原码、反码方式存在两个 0 的问题,而补码将负数反码加 1 去掉了负 0,且负数比正数能多表示一个数,还说明了补码加法处理简单,最后给出 16 位 -1 补码按位与去符号位的结果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

补码与符号位取反

先来一个 C 语言的小例子:

#include <stdio.h>
#include <stdint.h>

int main(void)
{
    int16_t n = -1;
    n &= 0x7FFF;        // 按位与
    printf("%d", n);    // 这里输出什么?
    return 0;
}

对于16位的整数 n ,按位与运行将最高位设置为0(符号位),得到的结果却不是 1 ,结果是 32767 。

原因在于有符号整数的实现方式。

有符号整数,最容易想到的方式是在最高位加一个符号位,0表示整数,1表示负数,其它位不变(保留原始值),也即是原码方式。但这个方式有一个问题,存在两个0,正0和负0,在计算时需要先判断符号位,然后才能决定用加法还是减法,机器计算不便。

另外一个方法是负数全部按位取反,也就是反码方式。这个运算就相对简单了,进行加法时,按位计算,0和0为0,0为1为1,1和1为0并产生进位,最高位有进位时,结果要加1,减法可处理为其负数的加法。但还是有点问题,还存在两个0,正0和负0。

问题是出现负数上,那么把负数的反码 + 1 ,不就把负0去掉了吗?还真的是这样,而同时负数比整数能多表示一个数(这是基于同余的)。

严格的表达为:

对于位数为 n 的整数,其补码 [x]补 为:(2^n + x) mod 2^n ,
表示的范围为 -2^(n-1) <= n < 2^(n-1) ,注意正数最大为 2^(n-1)-1
即:
当 0 <= x < 2^(n-1) 时,
[x]补 = x 的原码
当 -2^(n-1) <= x < 0 时,
[x]补 = 2^n + x 的原码。

而经验上,可看作负数的补码为其反码加1(特殊数 -2^(n-1) ) 的反码 :

x < 0 时:
[x]补 = [x]反 + 1
特殊数 [ -2^(n-1) ] = 100...0

它的加法处理非常简单,符号位也可以运行,

[x+y]补 = (2^n + x + y) mod 2^n = ((2^n + x) + (2^n + y)) mod 2^n = [x]补 + [y]补
[x-y]补 = (2^n + x - y) mod 2^n = ... = [x]补 + [-y]补

现在回到原来的问题,对于16位 -1 ,其补码为:

[-1]补 = [-1]反 + 1 = 0xFFFFF

按位与去掉符号位,得到的是 0x7FFF 也就是16位整数最大的正数( 2^15 - 1) 32767。

转载于:https://www.cnblogs.com/fengyc/p/6734887.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值