C语言— —进制

本文详细介绍了进制的概念,包括十进制、二进制、八进制和十六进制之间的转换方法,并重点讲解了二进制的存储单位。此外,还深入探讨了原码、反码和补码的表示方式,以及为什么计算机系统选择用补码存储整数。通过实例展示了从补码快速得到十进制整数的计算过程。
摘要由CSDN通过智能技术生成

本文主要介绍进制、进制转换、原码反码补码的知识。

1. 进制

本章主要介绍什么是进制。现有数字 6179,从右到左分别为个位、十位、百位、千位,这是我们小学的知识了(所以不用害怕知识有多难,我们小学就接触了)。

image-20210815204904774

6179 就是一个十进制数,而我们在平时的生活中接触到的也是十进制数。现在我们来说说十进制数的特点:

  • 从右到左,分别为个位、十位、百位、千位、万位…;
  • 每一位上的数字可以为0-9之间的任意一个数字;
  • 逢十进一;

在编程世界中,最基础的是二进制,那么什么是二进制呢?类比十进制,二进制有如下特点:

  • 我们也可以将二进制的数从右到左分为每一位;
  • 每一位上的数字要么是0,要么是1;
  • 逢二进一;

例如,二进制下的数字 10010。

除了二进制,我们还常用八进制、十六进制。再次总结一下进制的知识:

  • 对于n进制,每一位上的数字可以为[0,n-1]
  • 对于n进制,低位的数字逢n进一。

以十六进制为例,每一位上的数字可以为[0,15],例如:

image-20210815210125326

可是,这种表示方法有歧义,我们用一个方框表示一位,可是在实际使用中是没有这个方框的,那么就会显示如下图,可以有两种以上的理解:

image-20210815210345988

这就造成了歧义,原因是[10,15]的数字我们用了两位来表示,为了消除歧义,我们用A-F分别表示10-15:

image-20210815210058614

所以十六进制的每一位上的数字可以为[0,15],但是为了消除歧义,10-15分别用A-F来表示。

2. 进制转换

本节主要介绍同一个整数不同进制之间的转换。对于小数的进制转换,感兴趣的同学可以自行查阅资料。我们以角标 X ( n ) X_{(n)} X(n)表示X是n进制数。

2.1 十进制转换为其它进制

我们分别以二进制、八进制为例,介绍十进制是如何转换为其它进制的。

其实十进制转换为其他进制所采用的方法是一样的,假设十进制转换为n进制,那么该方法可以称为“除n取余,逆序排列”。更准确地描述为,现有一个十进制数x,将其转换为n进制数,则转换方法为:

  • 首先计算 x ÷ n = p … q,得到商为p,余数为 q;
  • 再根据上一步得到的商 p 继续同样的步骤 p ÷ n = p 1 . . . q 1 p_1 ... q_1 p1...q1,得到商为 p 1 p_1 p1,余数为 q 1 q_1 q1
  • 直到商为0;
  • 最后将余数逆序从左至右排列 p n p n − 1 . . . p 1 p p_np_{n-1}...p_1p pnpn1...p1p,则 p n p n − 1 . . . p 1 p p_np_{n-1}...p_1p pnpn1...p1p就是转换后的n进制数;

以十进制数 10 0 ( 10 ) 100_{(10)} 100(10)转换为二进制数为例:
第 一 步 : 100 ÷ 2 = 50...0 第 二 步 : 50 ÷ 2 = 25...0 第 三 步 : 25 ÷ 2 = 12...1 第 四 步 : 12 ÷ 2 = 6...0 第 五 步 : 6 ÷ 2 = 3...0 第 六 步 : 3 ÷ 2 = 1...1 第 七 步 : 1 ÷ 2 = 0...1 第一步: 100 \div 2 = 50 ... 0 \\ 第二步: 50 \div 2 = 25 ... 0 \\ 第三步: 25 \div 2 = 12 ... 1 \\ 第四步: 12 \div 2 = 6 ... 0 \\ 第五步: 6 \div 2 = 3 ... 0 \\ 第六步: 3 \div 2 = 1 ... 1 \\ 第七步: 1 \div 2 = 0 ... 1 \\ 100÷2=50...050÷2=25...025÷2=12...1:12÷2=6...06÷2=3...03÷2=1...11÷2=0...1
最后将余数逆序排列,得到 10 0 ( 10 ) 100_{(10)} 100(10)的二进制形式为 110010 0 ( 2 ) 1100100_{(2)} 1100100(2)

在实际的转换中,我们可以按照如下的写法进行简化:

img

同理,十进制数 10 0 ( 10 ) 100_{(10)} 100(10)转换为八进制数的步骤如下:

img

即十进制数 10 0 ( 10 ) 100_{(10)} 100(10)转换为八进制数为 14 4 ( 8 ) 144_{(8)} 144(8)

2.2 其它进制转换为十进制

现有一个n进制数 p x − 1 . . . p 1 p 0 p_{x-1}...p_1p_0 px1...p1p0,共有x位,则将其转换位十进制数的公式为:
在这里插入图片描述

例如,现有二进制数 1110110 0 ( 2 ) 11101100_{(2)} 11101100(2),转换为十进制数如下:

在这里插入图片描述

2.3 二进制、八进制、十六进制之间的转换

由于二进制、八进制和十六进制之间存在特殊的对应关系,所以二进制和八进制、十六进制之间的互相转换存在简便方法。

首先,我们先确定三位二进制数的对应关系:

000001010011100101110111
01234567

三位二进制数所对应的十进制数为0—7,这就是八进制中的八个数字。

二进制数转换为八进制数的方法如下:对于二进制数,从右到左,以三位二进制数为一组,若最后一组不足三位,则高位补零。然后依次将每组的二进制数按照对应关系转换为八进制数,得到的结果就是八进制数。

例如,现有二进制数 1100110101001 0 ( 2 ) 11001101010010_{(2)} 11001101010010(2),将其转换为八进制数的步骤如下:

首先从右到左以三位二进制数为一组:
11 001 101 010 010 11 \quad 001 \quad 101 \quad 010 \quad 010 11001101010010
可以看到最左边的一组(最后一组)不足三位,则最高位补零:
011 001 101 010 010 011 \quad 001 \quad 101 \quad 010 \quad 010 011001101010010
然后按照对应关系,将每组转换为八进制数:
011 001 101 010 010 = 3 1 5 2 2 = 3152 2 ( 8 ) 011 \quad 001 \quad 101 \quad 010 \quad 010 = 3\quad 1\quad 5 \quad 2\quad 2 = 31522_{(8)} 011001101010010=31522=31522(8)
即二进制数 1100110101001 0 ( 2 ) 11001101010010_{(2)} 11001101010010(2)转换为八进制数为 3152 2 ( 8 ) 31522_{(8)} 31522(8)

同理,二进制数转换为十六进制数,就是四位二进制数与十六进制数的对应关系:

00000001001000110100010101100111
01234567
10001001101010111100110111101111
89ABCDEF

转换方法类似:对于二进制数,从右到左,以四位二进制数为一组,若最后一组不足四位,则高位补零。然后依次将每组的二进制数按照对应关系转换为十六进制数,得到的结果就是十六进制数。

例如,现有二进制数 1110111101001 0 ( 2 ) 11101111010010_{(2)} 11101111010010(2),将其转换为十六进制数的步骤如下:

首先从右到左以四位二进制数为一组:
11 1011 1101 0010 11 \quad 1011 \quad 1101 \quad 0010 11101111010010
可以看到最左边的一组(最后一组)不足四位,则最高位补零:
0011 1011 1101 0010 0011 \quad 1011 \quad 1101 \quad 0010 0011101111010010
然后按照对应关系,将每组转换为十六进制数:
0011 1011 1101 0010 = 3 B D 2 = 3 B D 2 ( 16 ) 0011 \quad 1011 \quad 1101 \quad 0010 = 3 \quad B \quad D \quad2 = 3BD2_{(16)} 0011101111010010=3BD2=3BD2(16)
即二进制数 1110111101001 0 ( 2 ) 11101111010010_{(2)} 11101111010010(2)转换为十六进制数为 3 B D 2 ( 16 ) 3BD2_{(16)} 3BD2(16)

3. 二进制中的存储单位

对于二进制中的一位,我们称之为比特位(bit),即一位=1bit,在此基础上,有如下单位:

  • 1字节=8位,即1byte=8bit,缩写为1B = 8b
  • 1千字节 = 1024字节,即 1 K B = 2 10 B 1KB = 2^{10}B 1KB=210B
  • 1兆字节 = 1024千字节,即 1 M B = 2 20 B 1 MB = 2^{20}B 1MB=220B
  • 1吉字节 = 1024兆字节,即 1 G B = 2 30 B 1GB = 2^{30}B 1GB=230B
  • 1太字节 = 1024吉字节,即 1 T B = 1024 G B = 2 40 B 1 TB = 1024GB = 2^{40}B 1TB=1024GB=240B

还有更高的单位,但是平时也涉及不到,因此此处只罗列常见的。

4. 原码、反码、补码

4.1 原码、反码和补码

本文介绍整数的几种编码方式。

**原码:**原码将数字的二进制分为两部分,符号位和数字的绝对值二进制表示;对于正数来说,符号位为0;对于负数来说,符号位为1。例如,用8位二进制位来存储整数,10和-10的原码表示如下:

10:  0000 1010
-10: 1000 1010

反码:对于正数来说,反码就是原码;对于负数来说,反码就是在原码的基础上,符号位不变,其余位反转。例如,10和-10的反码如下:

10:  0000 1010
-10: 1111 0101

补码:对于正数来说,补码就是原码;对于负数来说,补码就是在反码的基础上,加1。例如,10和-10的补码如下:

10:  0000 1010
-10: 1111 0110

在C语言中,存储整数都是按照补码的形式来存储的。

从十进制整数到二进制补码的转换我们已经了解了,那么如何从补码快速得到十进制整数呢?
对 于 一 个 n 位 的 二 进 制 补 码 { x n − 1 , x n − 2 . . . x 1 , x 0 } 来 说 , 将 其 转 换 为 对 应 的 十 进 制 整 数 方 法 如 下 : { x n − 1 , x n − 2 . . . x 1 , x 0 } = − x n − 1 ∗ 2 n − 1 + ∑ k = 0 n − 2 x k 2 k 对于一个n位的二进制补码\{x_{n-1}, x_{n-2} ... x_1, x_0\}来说,将其转换为对应的十进制整数方法如下:\\ \{x_{n-1}, x_{n-2} ... x_1, x_0\} = -x_{n-1}*2^{n-1} + \sum_{k = 0}^{n-2}x^{k}2^k n{xn1,xn2...x1,x0}{xn1,xn2...x1,x0}=xn12n1+k=0n2xk2k

4.2 为什么用补码存储整数?

首先我们来看原码的不足之处:

  • 原码计算涉及负数的减法存在问题。例如,计算 1 - 1,1 - 1 也可以看成 1 + ( -1 ) ,则转换为原码(以8位二进制数来存储整数)为:

    1 + (-1) = 00000001 + 10000001 = 10000010 = -2
    

    这样的计算结果显然是不对的。

  • 在原码表示中,0有两种表示方式。

    00000000: +0
    10000000: -0
    

    在原码表示中,0分为了+0和-0,这显然是不符合我们的习惯的,0是不分正负的。

再来看看反码有何不足之处:

  • 反码对于两个负数的加法计算存在问题。例如,计算 - 1 + (-1):

    -1 + (-1) = 11111110 + 11111110 = 1 00000000 = 00000000 = 0
    

    由于只用8位二进制位来存储数据,所以最高位的1省去。最后结果为0,结果显然不对。

  • 在反码表示中,0仍然有两种表示方式。

    00000000: +0
    11111111: -0
    

为了解决原码和反码存在的问题,提出了补码。

参考资料

[1] 进制:https://zh.wikipedia.org/wiki/%E8%BF%9B%E4%BD%8D%E5%88%B6

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值