进制

进制

电子计算机,顾名思义,就是计算的机器。 因此,学习汇编语言,就不可避免地要和数字打交道。在这个过程中,我们要用到三种数制:十进制、二进制、十六进制。我们的目标是:

  • 熟透后两种数制,了解这两种数制的计数特点
  • 能够在这三种数制之间熟练地进行转换,特别是在看到一个二进制数时,能够口算出它对应的十六进制数,反之亦然。
  • 对于 0~15 之间的任何一个十进制数,能够立即说出它对应的进制数和十六进制数。

进制也就是进位制,是人们规定的一种进位方法。 对于任何一种进制—X进制,就表示某一位置上的数运算时是逢X进一位。 十进制是逢十进一,十六进制是逢十六进一,二进制就是逢二进一,以此类推,x进制就是逢x进位。

二进制计数法

关于二进制计数法

二进制逢二进一,所有的数组是0、1组成

当前的计算机系统使用的基本上是二进制系统,它的基数为2, 数据在计算机中主要是 以补码的形式存储 的 。

我们计算机也是一台机器,机器在做数学题是,也面临着一个如何表示数字的问题,比如你采用什么办法来将加数和被加数送到机器里。

答案是, 用高、低两种电平的组合来表示数字 。参与计算的数字通过电线送往计算机器,高电平被认为是“1”,低电平被认为是“0”,这样就形成了一个“0”和“1”组成的序列,如“11111010”,这就是一个二进制数,在数值上等于我们所熟知的十进制数 250。

从数学角度看,二进制计数法是现代主流计算机的基础。

  • 简化了硬件设计,因为它只有两个符号“0”和“1”,要得到它们,用最少的电路元件来接通或者判断电路就行了。
  • 二进制与十进制有着一对一的关系,任何一个十进制数都对应一个二进制,不管它有多大。

组成二进制数的每个数位,称为一个 比特(bit) ,而一个二进制数也可以看成一个比特串。很明显,它的数值越大,这个比特串说越长,这是二进制计数法不好的一面。

1、一个字节 = 8位(8个二进制位) 1Byte = 8bit;
2、一个十六进制 = 4个二进制位
3、一个字节 = 2个十六进制

口诀

  • 2^0=1=1b
  • 2^1=2=10b
  • 2^3=8=1000b
  • 2^4=16=10000b
  • 2^5=32=100000b
  • 2^6=64=1000000b
  • 2^7=128=10000000b
  • 2^8=256=100000000b
  • 2^9=512=1000000000b
  • 2^10=1024=10000000000b
  • 2^11=2048=100000000000b
  • 2^12=4096=1000000000000b

8421法则 : 将二进制的每一位数用相对就的 8、4、2、1 来表示,再通过“数字 ”相加就可以得到二进制数的数据

8 1000
4 100
2 10
1 1
1000
  100
    10
      1
--------
1 1 1 1


1 位数:如果是该数本身
2 位数:如果都有值是2+1
3 位数:如果都有值是4+2+1
4 位数:如果有值是8+4+2+1

二进制到十进制转换

每种计数法都有自己的符号(数符):

  • 十进制:0、1、2、3、4、5、6、7、8、9
  • 二进制:0、1
  • 十进制:0、1、2、3、4、5、6、7、8、9、a、b、c、d、e、f

这些 数字符号的个数称为基数 。也就是说十进制有 10 个基数,而二进制只有两个。

二进制和十都是进位计数法。进位计数法一个特点是,符号的值和它在这个数中所处的位置有关。

范例:十进制 365

\begin{equation*} 百位 3、十位 5、个位 6 = 3 \times 10^2 + 5 \times 10^1 + 6 \times 10^0 = 365 \end{equation*}

这就是说,由于所处位置不同,每个数位都有一个不同的放大倍数,这称为“ ”。每个数位的权是这个计算的(仅讨论整数): 从右往左开始,以基数为底,指数从 0 开始递增的幂

二进制转化为十进制

权值法:将2进制各个位数从0位开始乘以2的N次幂,将各个位数的结果相加。N代表位数

将上面的算式是把 十进制数“翻译”成十进制数。推广一下,将二进制数转换成十进制数。

范例: 10110001B

\begin{equation*} 10110001B = 1 \times 2^7 + 0 \times 2^6 + 1 \times 2^5 + 1 \times 2^4 + 0 \times 2^3 + 0 \times 2^2 + 0 \times 2^1 + 1 \times 2^0 = 177D \end{equation*}

上面公式里,10110001B 中 B(Binary) 表示这是个二进制数,D(Decimal) 表示 177 是十进制数。

十进制到二进制的转换

除2反序取余法:用十进制数除以2,分别取余数和商数,商数为0的时候,将余数倒着数就是转化后的结果。

将它不停地除以二进制的基数 2,直到商为 0,然后将每一步得到的余数串连起来即可。

img_20240305_024324.png

十进制的小数转换成二进制

小数部分和2相乘,取整数,不足1取0, 每次相乘都是小数部分 ,小数部分有几位就需几位。顺序看取整后的数就是转化后的结果。

如0.432只有3位,故只需3位。

img_20240305_024704.png
  • 乘的时候只乘小数部分
  • 0.432 只有 3 位,故只需 3 位
  • 0.432 的二进制数为:0.011

十六进制计数法

十六进制逢十六进一,所有的数组是0到9和A到F组成 字母不区分大小写

十六进制(英文名称:Hexadecimal),同我们日常生活中的表示法不一样,它由0-9,A-F组成, 字母不区分大小写 。与10进制的对应关系是:0-9对应0-9,A-F对应10-15。

十进制转化十六进制

除十六反序取余法: 用十进制数除以16,分别取余数和商数,商数为0的时候,将余数倒着数就是转化后的结果。

十六进制转化为十进制

权值法:

如 7 C 3

  • 第 0 位: \(3 \times 16^0 = 3\)
  • 第 1 位: \(12 \times 16^1 = 12 \times 16 = 192\)
  • 第 2 位: \(7 \times 16^2 = 1792\)
  • 1792 + 192 + 3 = 1987

十六进制的数和二进制数可以按位对应( 十六进制一位对应二进制四位 ),因此常应用在计算机语言中。

0101 0111 1010 1011 0101 0111 1101 0111 000
 5    7    A    B    5    7    D     7   0

十六进制转二进制

 A    B    4    2    D
1010 1011 0100 0010 1101

8421法则: 将各个位数的二进制用十进制中的【数字 】来表示多位的二进制数 通过【数字 】相加就可以得到二进制数的数据

8 1000
4 100
2 10
1 1
1000
  100
    10
      1
————
1 1 1 1

八进制

八进制逢八进一,所有的数组是0到7组成

八进制,Octal,缩写OCT或O,一种以8为基数的计数法,采用0,1,2,3,4,5,6,7八个数字,逢八进1。一些编程语言中常常以数字0开始表明该数字是八进制。

十进制转化八进制的方法 :

除八反序取余法: 用十进制数除以8,分别取余数和商数,商数为0的时候,将余数倒着数就是转化后的结果。

八进制转十进制 :

权值法:将8进制各个位数从0位开始乘以8的N次幂,将各个位数的结果相加。N代表位数

3703
第0位: 3*8^0 = 3
第1位: 0*8^1 = 0
第2位: 7*8^2 = 448
第3位: 3*8^3 = 1536
1536+448+3 =1987

8进制与2进制互转

八进制的数和二进制数可以按位对应( 八进制一位对应二进制三位 ),因此常应用在计算机语言中。

# 二进制转 8 进制
101 001 101 111 011
5    1   5   7   3

# 8 进制转二进制
 1   2   5   4  7
001 010 101 100 111

八四二一法则 :将二进制的每一位数用相对就的 8、4、2、1 来表示

  • 1 位数:如果是该数本身
  • 2 位数:如果都有值是2+1
  • 3 位数:如果都有值是4+2+1
  • 4 位数:如果有值是8+4+2+1

计算机内存数值存储方式

原码

一个数的原码(原始的二进制码)有如下特点:

  • 最高位做为符号位,0表示正,为1表示负
  • 其它数值部分就是数值本身绝对值的二进制数
  • 负数的原码是在其绝对值的基础上,最高位变为1

下面数值以1字节的大小描述:

十进制数  原码
+15 0000 1111
-15 1000 1111
+0  0000 0000
-0  1000 0000

原码表示法简单易懂,与带符号数本身转换方便,只要符号还原即可,但当两个正数相减或不同符号数相加时,必须比较两个数哪个绝对值大,才能决定谁减谁,才能确定结果是正还是负,所以原码不便于加减运算。

反码

  • 对于正数,反码与原码相同
  • 对于负数,符号位不变,其它部分取反(1变0,0变1)
十进制数  反码
+15 0000 1111
-15 1111 0000
+0  0000 0000
-0  1111 1111

反码运算也不方便,通常用来作为求补码的中间过渡。

补码

在计算机系统中,数值一律用补码来存储

补码特点:

  • 对于正数,原码、反码、补码相同
  • 对于负数,其补码为它的反码加1
  • 补码符号位不动,其他位求反,最后整个数加1,得到原码
十进制数  补码
+15 0000 1111
-15 1111 0001
+0  0000 0000
-0  0000 0000
#include <stdio.h>

int main()
{
  int  a = -15;

  printf("%x\n", a);
  //结果为 fffffff1
  //fffffff1对应的二进制:1111 1111 1111 1111 1111 1111 1111 0001
  //符号位不变,其它取反:1000 0000 0000 0000 0000 0000 0000 1110
  //上面加1:1000 0000 0000 0000 0000 0000 0000 1111  最高位1代表负数,就是-15

  return 0;
}

补码的意义

示例1:用8位二进制数分别表示+0和-0

十进制数  原码
+0  0000 0000
-0  1000 0000

十进制数  反码
+0  0000 0000
-0  1111 1111

不管以原码方式存储,还是以反码方式存储,0也有两种表示形式。为什么同样一个0有两种不同的表示方法呢?

但是如果以补码方式存储,补码统一了零的编码:

十进制数  补码
+0   0000 0000
-0  10000 0000由于只用8位描述,最高位1丢弃,变为0000 0000

示例2:计算9-6的结果

以原码方式相加:

十进制数  原码
9   0000 1001
-6  1000 0110
-------------
    1000 1111

以补码方式相加

十进制数  补码
9   0000 1001
-6  1111 1010
-------------
   10000 0011

最高位的1溢出,剩余8位二进制表示的是3,正确。

在计算机系统中,数值一律用补码来存储 ,主要原因是:

  • 统一了零的编码
  • 将符号位和其它位统一处理
  • 将减法运算转变为加法运算
  • 两个用补码表示的数相加时,如果最高位(符号位)有进位,则进位被舍弃

一个有符号的整型数据可以分为两部分一部分是符号位(在最高位)、一部分是数字位

无符号数据类型只包含数字位部分

signed int a= 1986(有符号标识 signed可以不用写)

二进制:11111000010

1986原码:0000 0000 0000 0000 0000 0111 1100 0010
-1986原码:1000 0000 0000 0000 0000 0111 1100 0010

1986反码: 0000 0000 0000 0000 0000 0111 1100 0010
-1986反码:1111 1111 1111 1111 1111 1000 0011 1101

1986补码: 0000 0000 0000 0000 0000 0111 1100 0010
-1986补码:1111 1111 1111 1111 1111 1000 0011 1110
1986 +( -1986)的结果:1 0000 0000 0000 0000 0000 0000 0000 0000

溢出 :在数据进行操作的时候会导致超出数据类型大小,会向前位进1,多于原始数据类型大小,会被系统自动舍弃 保留从后面开始数据类型大小的位数

  10+20
0000 1010
0001 0100
0001 1110
-10+-20

-10的补码:
原码:1000 1010
反码:1111 0101
补码:1111 0110

-20的补码:
原码:1001 0100
反码:1110 1011
补码:1110 1100

-10+-20相加:
     1111 0110
     1110 1100
补码:1110  0010
反码:1110 0001
原码:1001 1110 16+8+4+2=-30

练习:

用生辰年份年去生辰日期
1992
-326

1、将10进制转化为二进制
1992 :0000 0000 0000 0000 0000 0111 1100 1000
-326 :0000 0000 0000 0000 0000 0001 0100 0110

2、加符号位将数据变为原码     
1992 :0000 0000 0000 0000 0000 0111 1100 1000
-326 :1000 0000 0000 0000 0000 0001 0100 0110

3、转化为反码
1992 :0000 0000 0000 0000 0000 0111 1100 1000
-326 :1111 1111 1111 1111 1111 1110 1011 1001

4、将反码+1转化为补码     
1992 :0000 0000 0000 0000 0000 0111 1100 1000
-326 :1111 1111 1111 1111 1111 1110 1011 1010

5、计算补码     
1992 :0000 0000 0000 0000 0000 0111 1100 1000
326 :1111 1111 1111 1111 1111 1110 1011 1010
结果  :  1 0000 0000 0000 0000 0000 0110 1000 0010

6、将数据转化为10进制
110 1000 0010
2+128+512+1024 = 1666