• 注册
  • 生活易 生活易 关注:4 内容:33

    计算机为什么认识0和1?

  • 查看作者
  • 打赏作者
  • 当前位置: 超典 > 生活易 > 正文
    • 生活易
    • LV7
      VIP5
      ⚔ 管理員

      一句话:计算机数据逻辑电路,利用二极管单向导电性产生的正反电流,分别表示0和1。

             

      大家应该都知道,计算机是不理解它输入输出,也就是我们输进去和看到的那些内容的,它只是在根据既定的规则将输入的数据进行特定的处理,然后再输出,由于计算机内数据和指令的存储和处理都是由晶体管和门电路等元件完成的,而这些元件实际上都只能表达出两种状态:开和关,这也是唯一能真正被计算机所“理解”的两个东西。这种特性正好与二进制的理念不谋而合,因此二进制就理所当然的成为了计算机的基础计数法,人们一般用1代表晶体管的“开”状态,0代表“关”的状态。计算机的一系列理论和结构进化都是基于二进制进行的。最早的计算机ENIAC上的程序也是直接由二进制代码构成,再手动改变计算机的硬件结构以实现编程,这种直接由二进制代码组成的程序语言叫机器语言
       。

      从最初只能通过修改硬件编程的ENIAC到现在各种形态的超级计算机,非专业人士可能很难想象,计算机那些绚丽多彩的输出:美丽的图像,美妙的声音以及其他的所有,在最本质上都是由一串0和1组成的。或许你现在明白为什么以黑客帝国为代表的那些科幻电影会用一串串0和1组成的数据流来代表虚拟世界了,但那些0和1到底是怎样输入到计算机中被它们所理解,再通过计算成为我们我们想要的信息的呢?计算机的结构从无到有,从简单到复杂的过程中凝聚了无数天才的心血。哪怕用头脑模拟一下这其中的过程都会让人感到头疼,但经过技术日积月累的发展,在一代又一代专家们的努力下,现在的计算机已经能在须臾之间完成大量这样的运算并将我们想要的虚拟世界呈现在我们眼前,这或许也是计算机的迷人之处之一吧。

      大家应该都知道,计算机是不理解它输入输出,也就是我们输进去和看到的那些内容的,它只是在根据既定的规则将输入的数据进行特定的处理,然后再输出,由于计算机内数据和指令的存储和处理都是由晶体管和门电路等元件完成的,而这些元件实际上都只能表达出两种状态:开和关,这也是唯一能真正被计算机所“理解”的两个东西。这种特性正好与二进制的理念不谋而合,因此二进制就理所当然的成为了计算机的基础计数法,人们一般用1代表晶体管的“开”状态,0代表“关”的状态。计算机的一系列理论和结构进化都是基于二进制进行的。最早的计算机ENIAC上的程序也是直接由二进制代码构成,再手动改变计算机的硬件结构以实现编程,这种直接由二进制代码组成的程序语言叫
       机器语言
       。

      不过二进制对于人类来说实在是太艰深而且麻烦了。虽然世界上绝对不缺能够玩得转二进制的大神,但对于更多的普通人来说,学习一种新的进制的门槛太高了。因此在早期大家经历了那段必须用二进制代码编写程序的经历之后,更高级的编程语言被一些神人开发出来了。最初的这种高级语言,叫汇编语言
       。

      这里说的“高级”同我们日常生活中接触到的“高级”这个词有所区别。它并不是想将这些语言分出一个三六九等,这点我们在后面就会明白,我们先来解释一下汇编语言的意义。简单的说,汇编语言可以理解成机器语言的一种“翻译结果”,把0和1组成的代码翻译成更容易被人类理解的形式,这样人们在编程的时候就更容易理顺思路,并且编程的过程也会更方便,而且这种从机器语言到汇编语言的翻译对应关系并不是一成不变的,而是可以由汇编语言的开发者随意规定的(这种可定制性也是现今编程语言百花齐放的原因)。不过这样一来也就意味着人们用汇编语言编出来的程序计算机无法直接理解,这时就又到了翻译的时候了。这种语言之间的翻译是由汇编语言软件中专用的翻译程序自动完成的。这样,编程的难度成功被降低了。

      举一个很简单的例子,下面是一个“非”门,它唯一的作用是当输入端是高电平(一般认为代表1)的时候,输出端会输出低电平(一般认为代表0),单独的一个非门并没有太大的意义,不过如果你将它放入一个具体的电路中,就会有奇迹发生。想象一下,如果有这样一盏灯:要求你不断检查它的状态,看到它开着的时候就需要把它关上,看到它关着的时候就需要把它打开(虽然并不会有这种事情发生……我就是举个例子),如果你觉得太累的话,就可以写个程序来完成这件事,你可能会想用0来代表“灯关着”,用1来代表“灯开着”,当然你想反过来也行,那么这个程序的逻辑部分就是这样。

      这正是这个“非”门能完美实现的功能,为了描述方便,我在这里使用我提出来的定义,即1代表灯开着,你会发现这个程序能准确的实现你所期望的事:当“A=1,即灯为打开”的时候,它会输出Y=0,也就是把灯关掉,反之亦然。把这个程序的其余部分编好之后,你就可以去安心做别的,把这件愚蠢的事交给程序了。不知道你意识到没有,在这个过程中,你已经创造出了基于这个非门电路的一个属于你自己的汇编语言程序。在这个程序中,你用“灯开着的状态”来代替了1,用“灯关着的状态”代替了0,如果你要写这么一个程序,可能它的逻辑部分可能会是这样的:

      X
       =
       灯的状态
       If X
       ==
       灯开着
        Then X
       =
       灯关着
         
       else
        X
       =
       灯开着
       end  
       if    是不是至少比

      X
       =
       lamp statusIf X
       ==
       1
        Then X
       =
       0
         
       else
        X
       =
       1
       end  
       if
       
      好理解一些,汇编语言做的其实就是这件事。当然,真正的汇编语言要比这复杂的多。

      对了,编程的难度降低的另一个原因是存储器的发展,最初的计算机上是没有专用的存储器的,计算机上可供调整的门电路就那么多,不仅麻烦,而且输入新程序的时候是一定会把旧程序抹掉的。1945年,ENIAC的顾问,传说中的冯·诺依曼首次提到了存储程序的概念,几乎同时图灵也想到了这个主意。后来,发达的存储设备让计算机可以非常方便的调用和修改以前的程序,也为更复杂的汇编、以及之后更高级的语言的发展打下了基础。

      没错,汇编虽然比机器语言简单多了,但是人们仍不满足,汇编语言一个比较大的问题是它必须针对它运行的硬件量身定制。比如我们上面举的那个程序的例子,在拥有一个非门的电路上它运行的很好,可是如果把这个电路中的逻辑元件换成“与”门(它的功能是,如果输入的两个电平都是高电平,则输出高电平,其它情况下都输出低电平),整个程序就完全无法适用了。因为非门与“与”门不仅功能不同,甚至连要求输入的数据量也不同。在汇编语言之上,人们又开发了许多更高级的语言,我们一般直接称其高级语言,典型的例子有BASIC、PASCAL等。这些面向问题的语言对问题的描述方式更接近人们的习惯,而且通用性更强,在运行这些高级语言的内容前,它们首先会被翻译成汇编语言,再翻译成机器语言,最后才能被机器所识别并运行。

      大家应该可以看出来这其中“高级”的含义了:越高级的语言,越容易被人理解,同时也意味着它要被机器所执行的话需要被翻译的次数就越多。也就意味着执行的速度可能会受到影响。至于我们日常使用中向电脑输入的数据和从电脑接收的数据,也都是事先被这样编程好的。我们管最底层执行机器语言的机器叫实际机器,也叫传统机器,而上面几层语言的编写和翻译系统我们则都称之为虚拟机器。

      现在家用计算机中在机器语言和汇编语言之间其实还有一层东西:操作系统。这个大家都很熟,它的作用是提供在汇编语言和高级语言的使用和实现过程中一些必要的基本操作,还起到了控制和管理、协调计算机整体软硬件资源的作用。它可以进一步方便汇编语言和高级语言的编程。总结起来,计算机的层次结构可以用下面的图来表示:

      到目前为止,讨论的内容大多是一些概念性的东西,但具体这些转换是如何在计算机中进行的呢?这需要先解释一下计算机的组成。

      现代的大多数计算机都遵循冯·诺依曼在1945年提出的概念,被称为“冯·诺依曼机”,演化至今,虽然PC的架构大多数要更复杂一些,但实际上一台最基础的冯诺依曼机只需要三个部分就可以正常使用:CPU、I/O设备和主存储器。CPU大家都很熟,主存储器就是之前提到过的用来存放程序和数据的存储设备,而I/O设备就是我们向电脑输入信息,以及电脑处理之后向我们输出各种结果所需要用到的各种设备。示意图如下:

      总线我们之后再说,计算机处理指令的关键在于CPU和存储器,当一条指令被输入到计算机中时,它的处理方式是有严格的流程的。我们以计算一个算式C=A+B为例。为了更详细的描述整个处理的过程,我们需要将上面的图进一步细化。

      图中把上面的算数逻辑单元ALU又分成了几个更细的部分,其中只有ALU是真正用于计算的,其它的其实都是寄存器 用来 存放运算过程中需要保存的数和产生的结果 。其中ACC(Accumulator)是累加器,MQ(Multiplier-Quotient Register)为乘商寄存器,X为操作数寄存器。在这篇文章里我们只讲加减法,因此不需要用到乘商寄存器。而控制器部分也分成了几个更细的部分,多出来的部分也是两个寄存器,IR(Instruction Register)是指令寄存器,用来存放当前要处理的指令内容,PC(Program Counter)是一个自动运行的程序计数器(也是一种寄存器),它存放着当前需要执行的指令的 地址,并且具有运行完后自动加一的功能。一般来说存储器中需要连续操作的指令都是连续放置的,因此只要加一就可以自动转移到下一条指令的地址,实现自动连续执行指令了。

      注:顾名思义,地址就是用来标识存储器中存储的数据所在位置的一个标记,它是一段拥有特定规律的数字,方便别的设备需要调用它的时候能方便的找到它。存储器中的所有数据都拥有自己的地址。(不然就没有意义了)

      主存储器里多的那两个MDR(Memory Data Register)和MAR(Memory Address Register)……没错你猜对了!也是寄存器……MDR用来存放需要送给CPU或者送回存储器的数据,而MAR用来存放要访问的单元的地址。

      当运算启动时,首先动作的是CPU的CU,它接到了来自I/O设备或其他设备的请求,于是开始行动,首先将PC中的值发送给主存的MAR,于是MAR会按照这个地址去寻找主存内的数据,找到后MDR会将这段数据传给IR,(由一串表示操作类型的数字和一串表示操作的对象的数字组成,这两组数字是连在一起传给IR的,CU有可靠的方法识别它的格式),CU分析这组数据后,依据指令的内容依此从内存中取出需要的数据。为了不让指令变得太长影响处理速度,一般会限制指令长度,我们在这里规定它们用的指令一次只能存放一个数据,也就是说CU每次发出读取存储器命令,只能取出这个加法运算中需要的一个数据,比如取出数字A,这时寄存器就发挥作用了,根据同A一起来的代表操作类型的命令,MDR会将数字A送往ACC等待进一步处理,完成后PC会自动加一,然后CU再将加一后的值发送给MAR,去取下一条指令,如此循环,直到所有需要的数据都被取完,在这里只需要取两个数:A和B,在加法运算中,加数取出来后会放在X里,所有数据准备就绪后,下一个执行的操作就会是运算操作了,一般运算操作会跟着第二个数一起来,也就相当于第一个取出的是A,第二个取出的是+B,它们组合在一起就可以完成运算了,在计算机内的表现则是CU控制寄存器ACC和X中的数在ALU中进行相加运算,然后把结果暂时存在ACC中等待进一步处理(如果算式还没算完,这个值还可以继续使用,算完了一般就是经由MDR送出去)。

      请登录之后再进行评论

      登录
    • 做任务
    • 发布内容
    • 签到
      繁體
      客服
    • 帖子间隔 侧栏位置: