答辩结束啦!!!来看看程序是怎么跑起来的吧

答辩完了,补充一下自己计算机方面的知识,强烈推荐这本书,因为看着收获满满,感觉自己可能记不住,记个笔记,强烈推荐看原书,写的真不错。

第一章 对程序员来说CPU是什么

CPU :Central Processing Unit(中央处理器) 由百万至数亿个晶体管构成。
CPU和内存称为IC(Integrated Circuit)集成电路。
CPU由寄存器,控制器,运算器和时钟构成,各部分由电流信号相互连通。
寄存器:暂存指令,数据等处理对象,可以理解为内存的一种但是效率极高。
控制器:吧内存上的指令,数据读入寄存器,并根据指令的执行结果来控制整个计算机。
运算器:负责运算从内存读入寄存器的数据。
时钟:发出CPU开始计时的时钟信号(有些计算机的时钟位于CPU外部)。
汇编语言采用助记符来编写程序,每一个原本是电气信号的机器语言都会有一个对应的助记符,助记符通常为指令功能的英文单词缩写。如mov和add分别是数据存储(move)和相加(addition)。
我们将汇编语言编写的程序转化成机器语言的过程称为汇编;
反之称为反汇编。
不同类型的CPU,其内部寄存器的数量,种类以及寄存器存储的数值范围都是不同的。
下图为寄存器的主要种类和功能
所以对于我们程序员来说,我们可以理解CPU是各种功能寄存器的集合体。其中程序计数器,累加寄存器,标志寄存器,指令寄存器和栈寄存器只能有一个,其他的一般有多个。
##程序计数器:
决定程序的执行流程。
我们来看看一个程序是怎么安装按照流程来跑的。当用户发出启动程序的指示后,操作系统就会把硬盘中保存的程序复制到内存中。下图就是讲123和456两个数值相加,并显示的一个过程。一个命令和数据通常被存储咋多个地址上,为了便于说明下图把指令数据分配到了一个地址中。在这里插入图片描述
地址0100是程序开始的位置,所以当操作系统把程序复制到内存中后,会将程序计数器设定为0100.CPU每执行一个指令,程序计数器里的值就会+1(当执行的指令占多个内存地址时,增加与指令长度相等的值)。然后程序就参照程序计数器里的值,从内存中读取并执行。

条件分支与循环条件

程序的流程分为顺序执行,条件分支和循环三种。
顺序执行:按照地址顺序执行指令。
条件分支:根据条件执行任意地址的指令。
循环:重复执行同一地址的指令。
下图展示了把内存中的数值123的绝对值输出到显示器上的一个过程。使用到了条件分支。当执行到0102时,如果累加寄存器中的值时正值,那么就执行跳转指令(jump指令)跳转到0104。
在这里插入图片描述
条件分支和循环中使用的跳转指令,会参照当前执行的运算结果来判断是否跳转。无论当前累加寄存器的运算结果为负数,零还是正数,标志寄存器都会将其保存(也负责存放一处和奇偶校验的结果)。
CPU在进行运算时,标志寄存器的数值会根据运算的结果自动设定。条件分支在跳转指令钱会进行比较运算。运算结果的正,零,负三种专状态有标志寄存器的三个位表示。如下图,是一个32位CPU的标志寄存器的示例,前三个位的值分别表示正数,零和负数。
在这里插入图片描述
CPU中执行的比较机制就是通过减法运算,一定要记牢。例如,假设要比较累加寄存器中存储的XXX值和通用寄存器中存储的YYY值,执行比较指令后,CPU的运算装置就会执行XXX-YYY的减法运算,再将执行的结果保存到标志寄存器中。结果为正表示XXX比YYY大,零表示XXX等于YYY,负表示XXX比YYY小。

函数的调用机制

哪怕是高级语言编写的程序,函数调用处理也是通过把程序计数器的值设定成函数的存储地址来实现的。但是这与条件分支,循环的机制有所不同,因为单纯的跳转指令是无法实现函数的调用的。函数调用需要执行完函数之后再返回到函数的调用点(函数调用指令的下一个地址)。
在这里插入图片描述
如上图是一个函数调用的过程,我们发现通过跳转指令吧程序计数器的值设定为0260也可以实现函数的调用(函数调用原点和被调用函数之间的数据传递可以通过内存或者寄存器来实现),但是当我们走到0354时,我们需要跳转到0154(函数调用指令的下一个指令),但是这个操作却无法实现(我们并没有保存0154,所以无法直接返回到0154)。
所以我们需要重新定义指令,使得该指令能够实现将0154(函数调用指令的下一个指令)保存到某存储结构中,当函数返回时,在从该存储结构中取出0154并跳转。
机器语言call和return指令能够解决这个问题。函数调用使用的是call指令而不是跳转指令,在将函数的入口设定到程序计数器之前,call指令会把调用函数后要执行的指令地址存储在名为栈的主存中。函数调用完毕后再执行return命令,return命令就是讲保存在栈中的地址设定到程序计数器中。 在这里插入图片描述

通过地址和索引实现数组

我们现在来看一下基址寄存器和变址寄存器。通过这两个寄存器,我们可以对主内存上特定的内存区域进行划分,从而实现类似数组的操作。
首先我们讲计算机内存上00000000-FFFFFFFF的地址划分出来。那么只要有一个32位的寄存器即可查看全部的内存地址。但是如果想想数组那么分割特定的内存区域以达到连续查看的目的使用两个寄存器会更方便一些。例如查看10000000-1000FFFF地址时,我们可以将10000000存入基址寄存器,并使变址寄存器从00000000-0000FFFF变化。CPU在查看时则会将基址寄存器+变址寄存器的值解释为实际查看的内存地址。变址寄存器的值就相当于高级寄存器中数组的索引功能。
在这里插入图片描述

CPU的处理其实很简单

cpu能进行的处理其实很简单。(下图中外围设备指的是鼠标,键盘等)
在这里插入图片描述

第二章

数据是用二进制数表示的

问题1:补码表示的二进制数11111111,用十进制表示是多少?
知识点1:正数的原码,反码,补码都是一样的。
知识点2:二进制第一位是符号位,1表示负数,0表示正数。取反时符号位不变。
负数的:

取反
加1
原码
反码
补码

第一位是1所以是一个负数,逆向操作,先减一得到反码为11111110
。再取反得到原码为10000001所以该数为-1。

问题2:补码形式的8位二进制数10101010,用十六位的二进制数怎么表示?
符号位向前补满。11111111 10101010

2.1用二进制数表示计算机信息的原因

计算机内部是由IC(集成电路)构成的。IC有好几种不同的形状,有的像一条黑色蜈蚣,在其两侧有数个乃至数百个引脚;有的则想插画用的针盘,引脚在IC内部并排排列着。IC所有的引脚只有直流电压0V或5V两个状态(特殊的IC不考虑)。所以计算机只能表示两个状态。
在这里插入图片描述
二进制数的位数一般是8位,16位,32位…也就是8的倍数,这是因为计算机所处理的信息的基本单位是8位二进制数。8位二进制数称为一个字节,位是最小单位,字节是基本单位。内存和磁条都使用字节单位来存储和读写数据。
用字节单位处理数据时,如果数字小于存储数据的字节数,那么高位上就用0填补。
计算机在做减法运算时,实际上内部做的是加法运算。所以在表示负数时需要用补码的形式表示。补码就是用正数表示负数,所以减法运算的时候就可以使用补码与正数相加。(之前也就知道计算机底层使用的是补码形式,具体为什么之前还疑惑过,但是百度搜不到就不了了之了,这本书确实很不错)
举个例子 -1的补码是1111 1111 ,这时候我们找一个5,他的原码是0000 0101那么5-1怎么计算的呢,就是5+(-1)=0000 0100=4。自己可以举两个例子,自己试试。
书中取补数的图解
编程语言包含的整数类型中,有的可以处理负数,有的不可以处理负数。例如c语言中有不能处理负数的unsigned short范围是
-32768–32767,也有可以处理负数的short类型范围是0–65535。
仔细思考一下补数的机制我们就可以知道为什么负数可以到达-32768而正数只能到达32767。首先我们很容易就可以根据古典概率知道第一位是0(正数),第一位是1(负数)的个数是一样的。但是我们发现0是用0000 0000表示,所以占用了一个位置。而1开头的数字1000 0000,根据原码,反码,补码的转换规则可以知道1000 0000转换成原码是1000 0000,是不是很惊奇,我第一次的时候也是十分震惊,来回算了好几遍才确定的。该原码中的第一个1并不是符号位,而是表示32768,而该数是一个负数所以1000 0000表示-32768。

2.5逻辑右移和算术右移的区别

没啥好记得,都是基础,右移时使用符号位填充,符号扩充时也是一样。
。。。。。。。
逻辑运算符更加简单

第三章 计算机进行小数运算出错的原因

一个问题

  public static void main(String[] args) {
        double ans=0;
        for (int i = 0; i < 100; i++) {
            ans+=0.5;
        }
        System.out.println(ans);
    }

结果是9.99999999999998
一个知识点:计算机小数位表示的方式。1011.0011 就是下图的结果。其实仔细思考与十进制表示还是有很大的共通性。
在这里插入图片描述

3.4什么是浮点数

想上图的1011.0011的表示方式完全是书面的二进制小数表示形式,在计算机内部是无法使用的。计算机底层使用的是浮点数double和float。
浮点数是指用符号,尾数,基数和指数这四部分来表示的小数。因为计算机内部使用的是二进制数,所以基数自然就是2。所以在计算机底层只需要保存符号,尾数,指数这三部分就能表示浮点数。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
看到了这儿要是能理解肯定最好啦。看不懂的可以自己去找原书,原书写的更详细,之前也找过很多资料都没有这本书写的直接一看就懂了,嘿嘿。我也试着将我的思路分享一下。
如果要你来设计一个数据结构来存储浮点数,你会怎么设计。其实也不难,思路也很清晰,因为图3.3的式子可以表示类似1011.0011这种书面形式的小数表达式,所以是用这种表达式,而这个表达式由四个部分构成,因为计算机底层使用的式二进制所以指数部分已知是2。所以只需要知道符号,指数,和尾数部分就可以表示。
这时候你决定使用一个32位的数据结构来表示单精度浮点数,用一个64位的来表示双精度浮点数。首先他们都需要有 一个位来表示符号剩下的31位和63位根据需求拆开表示指数和尾数即可。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值