跳至主要內容

原码与补码

yczha大约 2 分钟AlgorithmAlgorithm

本文介绍计算机中的原码和补码表示法

原码表示法

将十进制数转为二进制即为源码表示,比如,将2表示为一字节8位的原码:210=000000102

如果是有符号数,比如C++中的int类型,那么就需要一位来表示符号,计算机中用0表示正数,1表示负数。

这样,+2表示为:+210=0,00000102

开始的第一位表示为符号位,-2表示为:210=1,00000102

补码表示法

虽然原码表示法人类理解起来是最容易的,但是却不利于计算机进行运算,因此计算机中实际使用的是补码表示法,补码规则也不复杂,对于正数来说,原码表示跟补码表示一致,对于负数来说,补码表示在原码的基础上,符号位保持不变,而数值部分取反加一。

例如,+2的原码表示转换为补码表示为:

+210=[]0,00000102=[]0,00000102

-2的原码转为补码则为:

210=[]1,00000102=[]1,11111102

计算C++int的表示范围

清楚了原码和补码表示之后我们来计算C++中的int表示范围。

首先,int型数据在C++语言g++编译器下使用4个字节表示:

int lengthOfInt=sizeof(int);
//结果为4(字节)

这样,一共就是4*8=32

32位除去一位符号位,剩余31位,那么int表示的最大正数就是:

int maxInt=pow(2,31)-1;
//maxInt=2147483647

最小负数呢?

int minInt=-(pow(2,31)-1)
//minInt=-2147483647

你觉得是这样吗?

如果你觉得是的话,你就错了,首先考虑+0的原码表示:

+010=[]0,00000000000000000000000000000002

那么-0

010=[]1,00000000000000000000000000000002

你会发现,0有两种表示,这样其实是一种浪费,因为在计算机中,把-0表示为最小的负数,其补码

010=[]11,000000000000000000000000000000002

你会发现这个数已经超过32位产生溢出了,因而实际的表示就是:

010=[]1,000000000000000000000000000000002

好了,现在你已经理解了原理了,那么求得以下的结果你应该不会意外了吧:

//求解int的范围

#include <iostream>
#include<cmath>
#include<limits>

int main(char* args,char** argv){
    std::cout<<"Size of int(Bytes):"<<sizeof(int)<<std::endl;
    std::cout<<"Max of int:"<<std::to_string(int(pow(2,31)-1))<<std::endl;
    std::cout<<"Min of int:"<<std::to_string(int(pow(-2,31)))<<std::endl;
    std::cout<<"Max of INT:"<<INT_MAX<<std::endl;
    std::cout<<"Min of INT:"<<INT_MIN<<std::endl;
    return 0;
}

使用g++编译:

g++ range_of_int.cpp -o range_of_int.exe

运行:

$./range_of_int.exe
Size of int(Bytes):4
Max of int:2147483647
Min of int:-2147483648
Max of INT:2147483647
Min of INT:-2147483648