编程基础(一)——二进制

计算机中的二进制

1tb = 1024gb

1gb = 1024mb

1mb = 1024kb

1kb = 1024b

1b = 8bit

上面这些想必大家已经知道了,这个单位bit是信息的最小单位,一个它所提供的信息量就是两个选项中的一个,0 或 1,这两个值也可以被解释为逻辑值(真/假、yes/no)、代数符号(+/-)、激活状态(on/off)或任何其他两值属性。

那么内存可以看作是一排排的开关,因为开关只有开和关两种状态,所以一个开关存一个 bit 的数据刚刚好,如果我只有一个开关,那我我能存 0(关)和 1(开),如果我有两个开关,根据排列组合我们可以知道我们能够存 4 种情况,"-"前面代表第一个开关,"-"后面代表第二个开关,那么就有这几种情况:0-0,0-1,1-0,1-1,到这里我们回忆一下幼儿园学加法时的口诀:”满 10 进 1”,这是我们十进制中的运算,二进制中的运算为”满二进一”,想象一下,我们有一个奇怪的钟表,上面只有 0 和 1 两个刻度,有类似时针分针秒针的三根针在走,现在秒针停留在 1 秒上面,那下一秒秒针会走到 0 秒上,但是分针会向前进一格,这就是”满 2 进 1”。回头看两个开关的那几种情况,0-0 代表 0,0-1 代表 1,1-0 代表 2,1-1 代表 3。如果有很多很多的开关,那能存的数据就会变的很多很多。这就是冯·诺依曼计算机的存储原理。碰巧的是,平常我们能接触到的计算机都是冯·诺依曼计算机(为啥?因为能接触到其他体系结构计算机的大佬不会有兴趣来看这篇博客的。)

计算机怎么进行运算

上面我们知道了计算机是怎么存储的,那计算是怎么计算的呢?要计算 1+2 那应该先把 1 和 2 先存下来,然后再计算,首先我们要知道一个概念:计算机只会做加法,不会减法,乘法,除法等等等等

减法

那减法是如何做的呢?减一个数等于加上它的相反数。2-1=2+(-1),那减法的问题就变成了负数如何在计算机中表示?这个问题可以看我们的另一篇文章,“传送门:编程基础(二)——原码,反码,补码”。

乘法

乘法呢?乘法是通过加法和移位运算来实现的。移位运算可以看我们的另一篇文章,“传送门:编程基础(三)——位运算,我们先简单说一下乘法的实现。我们小时候计算乘法的时候怎么计算的呢?比如计算11 * 9,分解成11 * 9 = 10 * 9 + 1 * 9,二进制也类似。

1
2
3
1011                           1000           10            1
1001 * ==> 1001 * + 1001 * + 1001 *
-------------- ------- ------- -------

二进制乘法可以这样理解:1011 * 1001 = 1000 * 1001 + 10 * 1001 + 1 * 1001,接着计算1000 * 100110 * 1001,这边用到了移位运算,1000 * 1001等于1001左移 3 位,即1001000,而10 * 1001等于1001左移 1 位,即10010,最后加起来1001000 + 10010 + 1001 = 1100011,转为二进制即为99,这只是为了便于理解而这样举例子,其实计算机并没有进行分解,它的运算通过进行移位运算、加法运算和寄存器存储进行的。具体执行方法感兴趣的同学可以自己查查看。

除法

除法就是乘法的逆运算,我们直接看一个不能整除的,比如20/9,二进制的运算就是10100/1001。计算方法就是从被除数(10100)最左位加上余数寄存器的值与除数进行比较,看起来比较晦涩,那我们直接上例子:

  • 初始余数寄存器为 0

    1
    2
    被除数      除数      余数      商
    10100 1001 0
  • 被除数最左位1 + 余数寄存器0=1,小于除数1001,商中存入0,然后被除数左移一位,变成0100,余数放到寄存器中存起来,即1

    1
    2
    被除数      除数      余数      商
    0100 1001 1 0
  • 接着比较最左位0 + 余数寄存器1 << 1(这里1 << 1的原因是因为余数的位数比最高位高出一位,余数理应左移一位后再加)=10,依然小于除数1001,商中存入0,然后被除数左移一位,将余数放入寄存器。

    1
    2
    被除数      除数      余数     商
    100 1001 10 00
  • 接着比较最左位1 + 余数寄存器10 << 1=101,依然小于除数1001,商中存入0,然后被除数左移一位,将余数放入寄存器。

    1
    2
    被除数      除数      余数      商
    00 1001 101 000
  • 接着比较最左位0 + 余数寄存器101 << 1=1010,大于除数1001,这里大于以后商中存入 1,然后被除数左移一位,将余数1010-1001=1放入寄存器。

    1
    2
    被除数      除数      余数      商
    0 1001 1 0001
  • 接着比较最左位0 + 余数寄存器1 << 1=10,小于除数1001,商中存入0,然后被除数左移一位,将余数放入寄存器。到这被除数位数没了,就已经算完了

    1
    2
    被除数      除数      余数      商
    1001 10 00010
  • 转成 10 进制就是余数为 2,商为 2

小结

今天我们讲到的是计算机底层的数据存储和运算大体上的原理,我们留了一个问题:负数如何表示。接下来我们会讲到负数在计算机中如何存储:传送门:编程基础(二)——原码,反码,补码。可能大家还会有其他的疑惑,比如“小数如何计算的?”等等,这些问题感兴趣的同学可以自己查查相关资料。

抛开我们背的乘法口诀来看,二进制的计算比 10 进制的计算运算规则简单很多,并且,在现实技术实现上也比较简单,逻辑电路的接通和断开就刚好可以表示01