本节主要讲计算机的编码存储格式和相应的变换。

机器数和真值

先来说两个概念:

  • 机器数:在计算机中的二进制表示形式,是可以表示符号的,比如正负数
  • 真值: 是计算机内真正的那个值,因为一般有一个bit表示符号位,所以看到的和实际表示并不一致

https://blog.csdn.net/qq_48486897/article/details/106653164

补码

计算机所有存储都是补码,得到结果也是补码

a = 3
b = 5
print("3&b = {0}".format(a&b))

print("-1 & -2 = {0}".format(-1&-2))

print("-2 & 6 = {0}".format(-2 & 6))

位运算在乘除法中的应用

print(" 1x2={0}".format(1<<1))
print(" 1x16={0}".format(1<<4))
print(" -10x4={0}".format(-10<<2))

print(" -40/4={0}".format(-40>>2))

二进制表示法

print("10={0}".format(bin(10)))
print("-10={0}".format(bin(-10)))

2. 原码

  • 符号位加上真值的绝对值
(+1)原码 = 0000 0001
(-1)原码 = 1000 0001 
八位取值范围是[1111 1111 - 0111 1111] = [-127 - 127]

3. 反码

  • 正数的反码是其本身
  • 负数的反码是在原码的基础上,符号位不变,其余各位取反
[+1] = [0000 0001]原码 = [0000 0001]反码
[-1] = [1000 0001]原码 = [1111 1110]反码

4. 补码

  • 正数的补码是本身
  • 负数的补码是原码基础上,符号位不变,各位取反,然后加1,即反码+1

5. 移码

  • 补码的符号位取反

5. 为什么使用这样的码值

  • 1-1的问题
(1 - 1)原码表示 = 1 + (-1) = [00000001]原 + [10000001]原 = [10000010]原 = -2 
(1 - 1)反码表示 = 1 + (-1) = [0000 0001]原 + [1000 0001]原= [0000 0001]反 + [1111 1110]反 = [1111 1111]反 = [1000 0000]原 = -0
(1 - 1)补码表示 = 1 + (-1) = [0000 0001]原 + [1000 0001]原 = [0000 0001]补 + [1111 1111]补 = [0000 0000]补=[0000 0000]原
(-1) + (-127) = [1000 0001]原 + [1111 1111]原 = [1111 1111]补 + [1000 0001]补 = [1000 0000]补
  • -128只是一个表示方法,是-0表示的-128,不是计算出来的,计算出来的是错误的,
[1000 0000]补码 = [0000 0000]原码 = 错误
  • 补码,修复了0的两个表示方法带来的问题,还可以表示一个最低位,所以八位二进制表示范围是[-128,127]

编码问题

  • 为什么需要编码
    • 计算机本质上只能表示二进制
    • 如何用一长串二进制表示复杂的信息
  • 编码简史
  • 二进制:
    • 数字->字符->数字
    • ‘a’ -> 97 编码和解码
  • 第一阶段: ASCII
  • 第二阶段:百花齐放,GB2312,GBK, BIG5 Latin1, ISO-8859-1, JIS, ANSI…
    • Latin1(ISO-8859-1)
    • 中国GBxxx
    • 韩国台湾Big5
    • 日本JIS
    • ANSI-MBCS(Muilti-Bytes Charecter Set,多字节字符集)
  • 第三阶段: Unicode+ISO

编码表示法

  • ASCII-American Standard Code for Information Interchange
    • 所有的控制字符(比如CR回车、DEL删除等)编码在0-31范围以及127中。
    • 把所有的标点符号,英文大小写全部放在32-126范围中。
    • 防止以后出现需要补充的情况,把128-255位这么多位置留出来,
    • 0xxxx xxxx, 高位为0
  • Latin1
    • 0-127的所有位置不动,那么可以兼容ASCII,二进制位0xxx xxxx
    • 128-255位置全部用完,二进制位1xxx xxxx
    • 128-159之间为控制字符,
    • 160-255位文字符号,
    • 其中包括了西欧语言、希腊语、泰语、阿拉伯语、希伯来语
    • 欧元符号因为出现的比Latin1晚,没有编码位置
  • GBXXXXXXXXX
    • GB2312
    • 如果一个字节中第一位为0,那么这就是一个ASCII字符。 -如果一个字节中第一位为1,那么这个是汉字,认定需要2个字节才表示一个编码的文字。
    • 这个码表中包含汉字6763个和非汉字图形字符682个。
    • 还有很多的空间没有用到,索性全部预留了吧。
    • 0xxxxxxx:表示为ASCII字符 -1xxxxxxx 1xxxxxxx:表示为汉字
  • GBK
    • 在GB2312基础上添加汉字
    • 兼任GB2312和ASCII
    • 0xxxxxxx:表示为ASCII字符
    • 1xxxxxxx xxxxxxxx:表示为汉字
    • GB18030
    • 2/4位混编
  • Unicode
    • 只是一个码表,具体实现没有规定
    • 0-0x10FFFF来映射这些字符,最多可以容纳1114112个字符
    • 中文的编码范围为4E00-9FCF,其中9FC4-9FCF之间的区间没有使用
    • 上述区间全部是汉字,不包含全角字符,不包含特殊文字
    • UTF=UnicodeTransformationFormat
    • UTF-8

        0x0000~0x007F  (0 ~ 127) 	1字节 	0xxxxxxx
        0x0080~0x07FF(128 ~ 2047)  	110xxxxx 10xxxxxx
        0x0800~FFFF(2048 ~ 65535) 	3字节 	1110xxxx 10xxxxxx 10xxxxxx
        0x10000~1FFFFFF(65536 ~ 2097152) 	4字节 	11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
        0x2000000~0x3FFFFFF 	5字节 	111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
        0x4000000~0x7FFFFFFF 	6字节 	1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
      
  • UTF-16, 32
    • UTF-16是早期Unicode遗留产物
    • UTF-32浪费空间
  • UCS-2
    • UCS=UniversalCharacterSet,通用字符集
    • UCS-2与Unicode相同
    • 采用2个字节,定长的表示每一个字符,所以总计可以表示2^16个字符
  • UCS-4
    • 第一个字节:表示组(group),最高位为0,则有128个。
    • 第二个字节:表示平面(plane),256个。
    • 第三个字节:表示行(row),256个。
    • 第四个字节:表示码位(cell),256个
  • 如果UCS-4前两个字节为0, 则就是CUS-2

概念解释

  • 大尾(BigEndian) 小尾(LittleEndian)
    • “汉” -> 6C49
    • 6C49 -> BigEndian
    • 496C -> LittleEndian
  • BOM
    • UTF-8 无字节顺序问题
    • UTF-16会出现问题:
      • “奎” -> 594E
      • “乙” -> 4E59
    • BOM-ByteOrderMark
      • “ZERO WIDTH NO-BREAK SPACE” -> FEFF, 在UCS中不存在
      • FEFF->BigEndian
      • FFFE->LittleEndian
      • UTF-8 用来表示编码, FEFF的UTF-8编码是EF BB BF, 用来表示此后编码是UTF-8编码

        Python的编码问题

  • str
  • bytes
  • bytearray

    b = bytes.fromhex(‘E4 B8 AD’) b b’\xe4\xb8\xad’ b.decode(‘utf-8’) ‘中’ str(b) “b’\xe4\xb8\xad’”

    ord(‘A’) 65 ord(‘中’) 20013 chr(65) ‘A’ chr(20013) ‘中’

  • len的单位是字符,不是字节
  • python文件默认utf-8编码,如果特殊需要,需要声明
    • 声明方式放在第一行,或者第二行
    • # ‐*‐ coding: windows‐1252 ‐*‐
  • 读写文件默认utf-8, 可以指定
  • code point方式比较字符串,可能会带来问题
  • 重音符号的表示
  • 使用 unicodedata.normalize 函数
  • Python源码中出现了解码错误,那么会产生SyntaxError异常

  • 其他情况下,如果发现编码解码错误,那么会产生UnicodeEncodeError, UnicodeDecodeError异常

参考资料

  • https://www.cnblogs.com/jessonluo/p/4800331.html
  • https://blog.csdn.net/xuejianhui/article/details/52576771
  • http://tools.jb51.net/table/gb2312