信息的表示与处理

2017年4月趁着临近毕业时间比较充裕,就买了一本深入理解计算机系统(第三版),这本书的第二版之前浅浅的读过一遍只对里面的编译与链接章节印象深刻,其他章节对我来说完全陌生,我深知这本书的好,于是重新拾起这本书。为了加深自己的记忆就开始写博客记录自己的读书笔记。

第二章 信息的表示与处理

  • 如果值x是2的n次幂就可以很轻松的通过下面这个公式直接转换为十六进制。

    n = i + 4j  其中i在[03]范围内

    整个转换的过程分为以下几步:

    1. 通过计算得出值x为2的n次幂

    2. 将n转换为 i + 4j,其中i在[0, 3]范围内

    3. 根据i的映射关系计算十六进制的第一位,其映射关系如下:

      i = 0 ==> 0、i = 1 ==> 2、i = 2 ==> 4、i = 3 ==> 8

    4. 拿到j的值在最后的十六进制值的后面添加j个0

  • gcc -m32选项可以编译出32位的程序,64位的系统是可以兼容32位系统运行的。

  • 大端法最高有效位在前面,而小端法最低有效位在前面,网络传输统一使用大端法(网络子节序),不同的CPU架构使用的字节序不一样(主机子节序)。

  • 二进制值是计算机编码、存储和操作信息的核心,由二进制编码衍生出布尔代数。

    a & (b | c) ==> (a & b) | (a & c)
    a | (b & c) ==> (a | b) | (a | c)
    x ^ y ==> (x & ~y) | (~x & y)
    (a ^ b) ^ a ==> b (利用这个特性可以实现原地交换两个数值)
    0 ^ x ==> x 
    x | y 本质上等同于将y中为1的每个位置上将x对应位也设置为1
  • 逻辑右移其左端补0,而算术右移其左端补充最高有效的值。

  • 补码和无符号数之间的转换(C语言中会隐式将有符号转换为无符号类型)

    1. 补码转无符号数

      x < 0 ==> x + 2^w
      x >= 0 ==> x
    2. 无符号数转补码

      cpp
      u <= 补码的最大值 ==> u
      u > 补码的最大值 ==> u - 2^w

  • 位数扩展

    1. 无符号数进行零扩展
    2. 补码数值进行符号位扩展
  • 位数截断

    1. 截断无符号数相当于对2^k取模
    2. 截断补码相当于先对2^k取模,然后利用无符号数转补码的规则将其转换为补码

    k为截断后的位数

  • 补码取非

    当x = -2^w-1也就是补码的最小值时,其非就是x本身
    当x > -2^w-1时,其非就是-x

    补码取非的两个方法如下:

    1. ~x + 1,先取反然后加1
    2. 将x转换为二进制,然后从最低位开始找到第一个1,这个1的左边所有位取反
  • 加法运算

    1. 无符号数加法

      x + y < 2^w 没有越界的情况下其值就是x + y
      2^2 <= x + y < 2^w+1 溢出的情况下其值是x + y - 2^w

      计算出来的结果 如果小于x或y中的任意一个就是溢出

    2. 补码加法

      x + y >= 2^w-1 是正溢出,其值为x + y - 2^w
      -2^w <= x + y < 2^w-1 正常情况,其值为x + y
      x + y < -2^w-1 是负溢出,其值为x + y + 2^w

      x > 0 并且y > 0 但是x + y的结果小于等于0 发生了正溢出

      x < 0 并且 y < 0 但是x + y 的结果大于等于0发生了负溢出

  • 乘法运算

    1. 无符号乘法

      (x * y) 对2^w取模
    2. 补码乘法

      将 (x * y) 对 2^w取模的结果转转换为补码

      无论是补码乘法还是无符号乘法其截断后的二进制表示都是相同的

      可以通过下面这段代码来判断两个数的乘法运算是否溢出

      imt tmult_ok(int x, int y) {
        int p = x * y;
        return !x || p / x == y;
      }
    3. 乘以一个常数

      ​ 乘法运算所需要的时钟周期一般都要比加法,减法以及位运算要多,所以编译器通常会将乘法运算转换为位运算

      1. 常数是2的幂
      无论是无符号乘法还是补码乘法乘以一个2^w的常数,相当于右移w位,最后再截断到指定位数
      1. 常数不是2的幂
      例如: x * 14 (x可以是任意值)
      1. 首先将常数转换为2进制 例如14转换为 00001110
      2. 将转换的二进制分成连续的01 (00000)(111)(0)
      3. 找到每一个连续的1组合,确定这个连续的1的起始位置n和结束位置m,对于14来说n = 3,m = 1
      4. 对于每一个连续的1求想乘后的值,最后全部想加,对于x * 14来说就是 (x << n + 1) - (x << m)
  • 除法运算

    1. 无符号除法除以2的幂

      x除以2^w的结果取整等同于x右移w位
    2. 补码除法除以2的幂,向下舍入

      当x >= 0和无符号除法一样,右移w位即可
      当 x < 0的情况分几种情况,当w=1的时候是不需要舍入的,当w > 1时需要舍入,并且时向下舍入(无条件进位)
    3. 补码除法除以2的幂,向上舍入

      为了让补码除法除以2的幂可以向上舍入需要在移位之前添加一个偏置值来修改这种不合适的舍入
      (x + (1<1) >>k 

      这个偏置值是利用了 x/y向上取整等于(x + y -1)/y 向下取整这一特性 (其中y大于0)

  • 浮点数

    占时没搞清楚,后续补上

你可能感兴趣的:(生活-读书-大事记)