C++中负数和补码的关系

今天在阅读关于树状数组和线段树的博客时遇到了一个问题:
对于一个int类型的正整数x,-x=x。列如x=6,-x=x=111110102
看到这里很😵,原来计算机中是用一个数的补码存储它的负数的。
可以用下面的代码验证一下,部分代码参考老王生涯:C++输出二进制数

#include <iostream> 
#include <bitset>
int lowbit(int x);
void printBinary(int x);
int main() {
	std::cout<<lowbit(6)<<std::endl;
	printBinary(6);
	printBinary(-6);
	std::cin.get();
	return 0;
}

int lowbit(int x) {
	return x & -x;
}

void printBinary(int x) {
	std::cout<<"Binary of "<<x<<":"<<std::bitset<sizeof(x)*8>(x)<<std::endl;
}

输出:第一行是lowbit函数求一个数二进制位上为1时的最低位,这个不用管。
在这里插入图片描述
计算补码的方式:我们都知道计算补码的方式是对这个数的二进制按位取反再加1。
对于补码的解释:这篇博客写得很好liu_runda:补码,我这里稍微修改一下。
对于补码更自然的解释是:对于一个正整数x,如果x是n位的二进制数,则x的补码为2n - x。也就是说x的补码在对2n取模后就是-x。因此,减去一个数就可以看作加上这个数的补码(在对2n取模的意义下),因为这个数的补码就相当于在取模意义下这个数的相反数。
到这里关于补码和负数的知识就介绍完了。

====================================================
有了这些知识后,就可以回答另外一个问题:32位机器int变量的最大值和最小值

对于正数的最大值:对于32位有符号int,除去一个最高位符号位后,还剩下31位,可以表示231个数,除去0后还剩下231 - 1个数,可以表示的最大数为232 - 1 = 0x7FFFFFFF。
可以验证一下:

int a = 0x7FFFFFFF;
std::cout<<a<<std::endl;
std::cin.get();

输出:
在这里插入图片描述
0111 1111 1111 1111 1111 1111 1111 1111这个二进制数也刚好是2147483647。
对于最小值,前面提到C++中的负数都是由对应的正数的补码存储的。
0的补码很特殊,现在来看一下
对0按位取反为:1111 1111 1111 1111 1111 1111 1111 1111,按位加1后为0000 0000 0000 0000 0000 0000 0000 0000。即0的补码还是0,即-0用0本身表示。
那么此时便可以用1000 0000 0000 0000 0000 0000 0000 0000 这个二进制数表示-2147483648,用代码验证一下:

int a = 0x80000000;
std::cout<<a<<std::endl;
std::cin.get();

输出:
在这里插入图片描述

====================================================
总结:
1.在C++中,负数以对应整数的补码形式存储。即对正数的二进制按位取反再加1。这里加号表示连接符。
2.减去一个数等于加上它的补码。
3.补码解释是2n - x。实际计算方式是按位取反再加1。

====================================================
2021/5/24
附上一道leetcode的题:不用加号的加法
做了这道题对计算机中存储负数的方式会有更深的理解

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值