编码与补码

  声明:这里所有知识都来自《深入理解计算机系统》——第2章 信息的表示和处理


  首先计算机和编译器支持多种不同方式编码的数字格式,补码编码是其中的一种,其他的比如ASCII、Unicode也都是编码方式。而补码作为一种编码方式,它本身的原理与按位取反没关系。在介绍它的编码原理之前,理解编码这一概念有助于我们加深对补码的认识?

1、为什么需要编码

  计算机存储和处理的是二进制数字(或称为位),编码决定了这些二进制数据会怎么被处理,即编码规定了数据的处理规则。
  一个典型的例子:假设在C语言中声明无符号整型unsigned int a=5和和有符号整型int b = 5,对应的都是4个字节,32位的数字,他们的二进制表示是一样的(计算机底层处理的是二进制数),如下
  a:0000 0000 0000 0000 0000 0000 0000 0101
  b:0000 0000 0000 0000 0000 0000 0000 0101
  虽然二进制表示一样,而且数值一样(都是5),但是计算机在处理不同类型的数据时,使用的是不同的编码方式。
  同样的,假如在C语言中声明一个字符char c = 48(与char c = '0’具有同样的效果),对应的二进制数是:
  c:0001 1000
  这些二进制数看起来都类似,但是通过声明数据的类型,编译器和计算机就能够知道怎么处理这些二进制数。


2、补码

  为方便阐述,将二进制数理解为位向量 x = [ x w − 1 , x w − 2 , . . . , x 0 ] [x_{w-1}, x_{w-2}, ..., x_{0}] [xw1,xw2,...,x0] (向量这种专业词有点唬人,其实就是把二进制数看成了一些有序的数的集合)。
  补码编码的定义: (见中文第3版45页)
  对于向量x = [ x w − 1 , x w − 2 , . . . , x 0 ] [x_{w-1}, x_{w-2}, ..., x_{0}] [xw1,xw2,...,x0](即一串二进制数):
  他的值为:
        f(x) = − x w − 1 2 w − 1 + ∑ i = 0 w − 2 x i 2 i -x_{w-1}2^{w-1} + \sum_{i=0}^{w-2}x_i2^i xw12w1+i=0w2xi2i (1)
  最高有效位 x w − 1 x_{w-1} xw1也称符号位。
  于是计算机按照这种方式来计算int型变量b的值。
  PS:有些时候可能会听到按位取反的说法,比如按位取反的理解一文中的阐述。但我们要明白的一点是:这种说法只是为了我们快速算得二进制与十进制的表示,是一种取巧的做法(这个规律是正确的),但补码编码的最初定义与按位取反无关。
  PS:补码主要用于表示有符号数(包含正数、负数和0),无符号数的定义则相对简单(具体定义在下文中)但不能表示负数。此外,曾经也有原码编码、反码编码也能表示有符号数,但是这两种方式都有一个奇怪的属性,就是对于数字0有两种不同的编码方式。目前,有符号整数几乎都用补码方式类编码。


3、无符号数与ASCII编码

  为了给出原理(编码方式)的不同,这里也给出无符号数与ASCII编码的编码原理:
  无符号数编码定义:
        f(x) = ∑ i = 0 w − 1 x i 2 i \sum_{i=0}^{w-1}x_i2^i i=0w1xi2i (2)
  这个和(1)对比,就能明白为什么补码中1称为符号位,而无符号数没有符号位。
  而字符型变量c则是有一个ASCII表来与之一一对应,处理字符的时候二进制数会被处理成表中对应的内容。
  


  最后应该明确的是,上面说的是C语言的规定,Java有不同的规定,这使得Java代码可移植性较好(可以再不同机器上运行,不用重新编译)。

你可能感兴趣的:(数据结构与算法)