zoukankan      html  css  js  c++  java
  • 二进制;16进制; Byte , Python的bytes类; Base64数据编码; Bae64模块;

    参考:中文维基

    • 二进制
    • 位操作(wiki)
    • Byte字节
    • 互联网数据处理:Base64数据编码
    • Python的模块Base64
    • 16进制简介
    • python: bytes对象
    • 字符集介绍:ascii

    二进制简介:

    In mathematics and digital electronics, a binary number is a number expressed in the base-2 numberal system or binary numeral system, which uses only two symbos: zero(0) and one(1)。

    在数学和数字电路(集成电路),二进制数字是以2个数字为基础的系统(或二进制数字系统)表示的数字,它只使用2个符号0和1。

    数字电子电路中,逻辑门的实现直接应用了二进制,因此现代的计算机和依赖计算机的设备里都用到二进制。

    每个数字代表一个bit(Binary digit)

    四则运算:

    • 加法:0+0=0,0+1=1,1+0=1,1+1=10
    • 减法:0-0=0,1-0=1,1-1=0,10-1=1
    • 乘法:0×0=0,0×1=0,1×0=0,1×1=1
    • 除法:0÷1=0,1÷1=1

    计算机对二进制数据进行的运算(+、-、*、/)都是叫位运算,即将符号位共同参与运算的运算。

     

    计算的效率:位操作(位运算)

    因为计算机的数据存储只有0和1,为了效率,直接对二进制数字进行计算,无需先把二进制的数转换为十进制再进行加减乘除。

    这就是汇编语言计算速度快于高级语言(比如C语言)的原因。当然代码的可阅读性就降低了。

    ➕法的例子,根据上面的四则运算规则,就可以通过二进制数进行计算了。

    35:  0 0 1 0 0 0 1 1
    47:  0 0 1 0 1 1 1 1
    ————————————————————
    82:  0 1 0 1 0 0 1 0

    乘法的例子

    int a = 3;
    int b = 2; #后面的b分别为4, 8
    int c = a * b;
    
    3:  0 0 0 0 0 0 1 1  *  2
    ————————————————————
    6:  0 0 0 0 0 1 1 0
    
    *********************************************
    
    3:  0 0 0 0 0 0 1 1  *  4
    ————————————————————
    12:  0 0 0 0 1 1 0 0
    
    *********************************************
    
    3:  0 0 0 0 0 0 1 1  *  8
    ————————————————————
    24:  0 0 0 1 1 0 0 0

     通过上面的规律可知,a*b,

     如果b满足2^N的时候,就相当于把a的二进制数据向左边移动,移动的位数是N,这叫做移位运算,是位运算的一种。

     所以用代码可以这么表示,a << N。

     本例子是 3<<1,  3<<2, 3<<3。

     如果b不等于2^N,编译器会将b拆分。例子:

    int a = 15;                 
    int b = 13;      =>        int b = (4 + 8 + 1)
    int c = a * b;            

    运算转换为 15 * 4 + 15 * 8 + 15 * 1, 进行位运算,代码就是:

    15 << 2 + 15 << 3 + 15 << 0

    除法和乘法的原理相同,不过是改成右移动了。

    参考:https://juejin.im/post/5a5886bef265da3e38496fd5

    十进数转成二进数

    例子:十进制数:59.25

    59是整数部分,0.25是小数部分。分别使用不同的计算方式:

    • 整数部分:
      1. 进行带余除法运算。得到一个整数和一个余数。
      2. 对得到的整数继续进行第一步操作。直到步骤N得到商数为0。(商数:除法运算的结果。一般是指整数部分)
      3. 把上面多次带余除法运算得到的余数按照步骤从后往前排列组合。方法:(N代表第N步骤的余数):N组合N-1组合..1。组合得到就是二进制的整数数字部分。本例得到111011。
    • 小数部分:
      1. 对小数部分乘以2,得结果x,取x的整数部分。
      2. 对结果x乘以2,取其整数部分。如此反复,直到乘法得到的数字的小数部分全部为0为止。
      3. 读取所有乘法计算后得到的数字的整数部分,从第一步到最后一步组合。得到二进制的小数部分。本例是01.
    整数部分:
    59 ÷ 2 = 29 ... 1
    29 ÷ 2 = 14 ... 1
    14 ÷ 2 =  7 ... 0
     7 ÷ 2 =  3 ... 1
     3 ÷ 2 =  1 ... 1
     1 ÷ 2 =  0 ... 1
    小数部分:
    0.25×2=0.5
    0.50×2=1.0

    最后得到二进制数字59.25(10) = 111011.01(2)

    二进位转成十进位

    整数部分的转换方法:个位数乘以2的0次幂, 然后10位数乘以2的1次幂,如此每加一位那么2的次幂就加1,最后把得到数字相加就是十进制数字。

    1001012 = [ ( 1 ) × 25 ] + [ ( 0 ) × 24 ] + [ ( 0 ) × 23 ] + [ ( 1 ) × 22 ] + [ ( 0 ) × 21 ] + [ ( 1 ) × 20 ]
    1001012 = [ 1 × 32 ] + [ 0 × 16 ] + [ 0 × 8 ] + [ 1 × 4 ] + [ 0 × 2 ] + [ 1 × 1 ]
    1001012 = 3710

    非整数部分的转换方法:利用负次幂。例如0.01(2)

    0 × 2−1 (0 × 12 = 0)
    1 × 2−2 (1 × 14 = 0.25)

    得到十进制数字:0.25


    位操作(wiki)Bitwise operation

    位操作程序设计中对位模式(bit patterns)或二进制数(binary numerals)的一元和二元操作。

    在许多古老的微处理器上(simple low-cost processors),位运算比加减运算略快,比乘法运算要快很多, 在除法上明显的快。

    现代处理器执行加法和乘法和位运算一样快,这是因为它们采用longer instruction pipelines and other architectural design choices, 但位操作降低资源的使用更节能。

    位云算符:Bitwise operators

    • not  取反:      ~  取反是一元运算符,对一个二进制数的每一位执行逻辑操作。使数字1成为0,0成为1。
    • or    按位或      |    处理两个长度相同的二进制数,两个相应的二进位中只要有一个为1,该位的结果值为1。
    • xor   按位异或  ^   
      • 对等长二进制模式或二进制数的每一位执行逻辑异或操作。操作的结果是如果某位不同则该位为1,否则该位为0。
      • 2020-1-12再理解:按位置对2个数比较,有差异则为真(1),无差异则为假(0)
    • and  按位与     &  处理两个长度相同的二进制数,两个相应的二进位都为1,该位的结果值才为1,否则为0。

    按位异或:

    汇编语言的程序员们有时使用按位异或运算作为将寄存器的值设为0的捷径。用值的自身对其执行按位异或运算将得到0。并且在许多架构中,与直接加载0值并将它保存到寄存器相比,按位异或运算需要较少的中央处理单元时钟周期。

        0101
    XOR 0011
      = 0110

    移位 Bit shifts

    移位是一个二元运算符,用来将一个二进制数中的每一位全部都向一个方向移动指定位,溢出的部分将被舍弃,而空缺的部分填入一定的值。在类C语言中,左移使用两个小于符号"<<"表示,右移使用两个大于符号">>"表示。

    算数移位 Arithmetic shift(具体见wiki)

    • ⬅️,补0
    • ➡️,复制。

    逻辑移动 Logical shift

    上一章讲二进制的乘法运算,就是逻辑移动。利用的是二进制数的特性。

    应用逻辑移位时,移位后空缺的部分全部填0。

    • 位移就是补0。zeros are shifted in to replace discarded bits。左位移,逻辑移动和算数移动一样。
    • 但是右移动,逻辑移动是插入0bit,而算数位移是复制bit。
    #乘法运算1*(2^3)
       0001(十进制1)
    <<    3(左移3位)
     = 1000(十进制8)
    
    # 除法运算10/(2^2), 移动第2次,得到2,去掉了小数部分。
       1010(十进制10)
    >>    2(右移2位)
     = 0010(十进制2)

    Circular shiift(具体见英文wiki)


    Byte

    字节(港澳台叫元组,Byte), 是数字信息的单位,最常见的是8个bits组成一个byte。

    从历史上看,byte是bit的数量,bit用于在计算机上给文本字符编码。基于这个原因,在计算机学,byte是最小的内存地址单位。

    • Byte缩写B.
    • Bit缩写b。

    1个8b的Byte,最大是11111111,转换为十进制是255。因此范围是0~255。

    ASCII码:一个英文字母占一个Byte.即8个bit。


    Base64(wiki)

    Base64是一种基于64个可打印字符来表示二进制数据的表示方法。

    可打印字符包括字母A-Za-z数字0-9,和2个特别字符+,/。合计64个。

    每6个bit表示一个Base64字符。

    Base64索引表:

    数值字符   数值字符   数值字符   数值字符
    0 A 16 Q 32 g 48 w
    1 B 17 R 33 h 49 x
    2 C 18 S 34 i 50 y
    3 D 19 T 35 j 51 z
    4 E 20 U 36 k 52 0
    5 F 21 V 37 l 53 1
    6 G 22 W 38 m 54 2
    7 H 23 X 39 n 55 3
    8 I 24 Y 40 o 56 4
    9 J 25 Z 41 p 57 5
    10 K 26 a 42 q 58 6
    11 L 27 b 43 r 59 7
    12 M 28 c 44 s 60 8
    13 N 29 d 45 t 61 9
    14 O 30 e 46 u 62 +
    15 P 31 f 47 v 63 /

    原理

    63(2) = 111111(2)

    所以只需6个bit就可以表示64个字符了。

    例子:

    编码"man"

    文本 M a n
    ASCII编码 77 97 110
    二进制位 0 1 0 0 1 1 0 1 0 1 1 0 0 0 0 1 0 1 1 0 1 1 1 0
    索引 19 22 5 46
    Base64编码 T W F u

    Man的ASCII编码对应十进制数字是77,97,110,转换为二进制数字见上图。共有24bit。

    把上面的24个二进制数字分割成4部分,每部分6bit。比如第一部分的二进制码:010011。

    4个部分转换为十进制是19,22,5,46。

    使用Base64编码,查看编码表,对应的字符是TWFu。

    本例子,Base64算法将3个字节的ASCII编码转换为了4个字符的编码。

    相比较ASCII码,Base64更节省空间。ASCII3个Byte,可以存3个字母,但Base64用3个Byte可以存4个字母。

    特殊的情况:编码"a"或“aa”这种不足3个字符的文本字符串怎么办?

    答案:很简单,为不足的二进制位后补上0即可。

    用途

    Base64常用于在通常处理文本数据的场合,表示、传输、存储一些二进制数据,包括MIME电子邮件XML的一些复杂数据。

    (更节省空间)

    在URL中的使用

    因为Base64更省空间,所以用于网络传输数据上有优势。在HTTP环境下被经常使用。因为数据库对%符号占用的问题。出现了改进版的Base64。但原理都一样。


    Python的base64模块

    此模块提供了将二进制数据编码为可打印的 ASCII 字符以及将这些编码解码回二进制数据的函数。

    它为 RFC 3548 指定的 Base16, Base32 和 Base64 编码以及已被广泛接受的 Ascii85 和 Base85 编码提供了编码和解码函数。

    它支持所有 base-64 字母表 (普通的、URL 安全的和文件系统安全的)。

    base64.b64encode(s)

    对bytes-like objects进行编码,并返回编码后的bytes对象。

    base64.urlsafe_b64encode(s)

    使用的是URL和文件系统安全的字母表,用-和_代替标准Base64的+和/。

    例子:

    >>> base64.b64encode(b'xfbxefxff')
    b'++//'
    >>> base64.urlsafe_b64encode(b'xfbxefxff')
    b'--__'

    bytes对象

    是由单个字节构成的不可变序列。

    表示 bytes 字面值的语法与字符串字面值的大致相同,只是添加了一个 b 前缀.

    例子:

    一个能处理去掉=的base64解码函数:

    import base64
    
    def safe_base64_decode(s):
        length = len(s)
        r = length % 4
        if r == 0:
          return base64.b64decode(s)
        i = 1
        while i <= r:
          s = s + b"="
          i += 1
        return base64.b64decode(s)
    
    # 测试:
    assert b'abcd' == safe_base64_decode(b'YWJjZA=='), safe_base64_decode('YWJjZA==')
    assert b'abcd' == safe_base64_decode(b'YWJjZA'), safe_base64_decode('YWJjZA')
    print('ok')

    ⚠️备注:

    去掉=后怎么解码呢?因为Base64是把3个字节变为4个字节,所以,Base64编码的长度永远是4的倍数,因此,需要加上=把Base64字符串的长度变为4的倍数,就可以正常解码了。

    另外baes64的方法是对Byte类对象编码和解码,所以字符串前面带字符b。


    16进制(wiki)

    十六进制(简写为hex或下标16)在数学中是一种逢16进1的进位制

    用数字0到9和字母A到F表示,其中:A~F相当于十进制的10~15,这些称作十六进制数字

    在历史上,中国曾经在重量单位上使用过16进制,比如,规定16为一

    现在的16进制则普遍应用在计算机领域,这是因为将4个Bit化成单独的16进制数字不太困难。1个字节(Byte)有8个bit,表示成2个连续的16进制数字。可是,这种混合表示法容易令人混淆,因此需要一些字首、字尾或下标来显示。

    例:

    F16的二进制表示为1111(2)

    016的二进制表示为0000(2)

    表示方法

    不同电脑系统编程语言对于16进制数值有不同的表示方式:

    C语言、C++、ShellPythonJava语言及其他相近的语言使用字首“0x”,例如“0x5A3”。

    最常用(或常见)表示十六进制数值的方式是将 '0x' 加在数字前,或在数字后加上小字 16。例如 0x2BAD 和 2BAD16 都是表示十进制的11181(或1118110), 用二进制表示则需要2个Bytes(16个bit): 0010101110101101。

    十六进制的转换

    十进制转十六进制,采用余数定理分解。类似十进制转换为2进制。除数改为16.

    例如将487710转成十六进制:

    4877÷16=304....13(D)

    304÷16=19....0

    19÷16=1....3

    1÷16=0....1

    这样就计到487710=130D16

    编程中的函式

    Python:

    int('ff', 16) #255,把ff16转换为十进制数字255
    hex(255) #0xff, 转换为16进制,用前标记符号0x表示

    Python:  bytes对象

    是由单个字节构成的不可变序列。

    bytes 函数返回一个新的 bytes 对象,该对象是一个 0 <= x < 256 区间内的整数不可变序列。它是 bytearray 的不可变版本。

    bytes 对象只负责以字节(二进制格式)序列来记录数据。

    如果采用合适的字符集,字符串可以转换成字节串;反过来,字节串也可以恢复成对应的字符串

    由于 bytes 保存的就是原始的字节(二进制格式)数据,因此 bytes 对象可用于在网络上传输数据,也可用于存储各种二进制格式的文件,比如图片、音乐等文件。

    转化方法

    1. 表示 bytes 字面值的语法与字符串字面值的大致相同,通过添加了一个 b 前缀,构建字节串。

    2.class bytes([source[, encoding]])

    参数

    • source: 为整数,返回一个长度为source的初始化bytes对象。
    • 如果 source 为字符串,则按照指定的 encoding 将字符串转换为字节序列 
    • 如果 source 为可迭代类型,则元素必须为[0 ,255] 中的整数;否则会报告❌ValueError: byte must be in range(0, 256)
    • 如果没有输入任何参数,默认就是初始化数组为0个元素。

    bytes 字面值中只允许 ASCII 字符(无论源代码声明的编码为何)。

    创建bytes对象的2种方式:

    • b"xxx",用字面量的方式创建
    • bytes()函数创建。例子:bytes(range(10)),创建由整数组成的可迭代对象。

    如果使用字符串,需要指定编码方式:

    b = bytes('h',encoding='ascii')  #利用内置bytes方法,将字符串转换为指定编码的bytes
    >>> bytes("h",encoding='ascii')
    b'h'
    >>> bytes.decode(b'x68')  #把b'x68'解码得到ascii对应的符号
    'h'

    3.

    调用字符串的encode()函数来转化成bytes对象的字节串。

    bytes.decode()可以反向转化成字符串。

    >>> b'x68'.decode()
    'h'
    >>> "h".encode()
    b'h'

    例子

    1.使用bytes()函数,例子:

     十进制99的16进制是0x63,对应的ascii码是小写字母c:

     64(10) = 0x40(16)  , 对应的ascii码是@

    >>> a = bytes([64,99])
    >>> a
    b'@c'

    2.

    >>> b1 = bytes()
    >>> b2 = b''
    >>> b3 = b'hello'
    >>> b3
    b'hello'
    >>> b3[0]
    104
    >>> b3[2:4]
    b'll'
    >>> b4 = bytes('你好,Python!', encoding='utf-16')
    >>> b4
    b'xffxfe`O}Yx0cxffPx00yx00tx00hx00ox00nx00!x00'

    备注:ascii字符集表

    计算机底层并不能保存字符,但程序总是需要保存各种字符的,那该怎么办呢?

    计算机“科学家”就想了一个办法:为每个字符编号,当程序要保存字符时,实际上保存的是该字符的编号;当程序读取字符时,读取的其实也是编号,接下来要去查“编号一字符对应表”(简称码表)才能得到实际的字符。

    所谓的字符集,就是所有字符的编号组成的总和。早期美国人给英文字符、数字、标点符号等字符进行了编号,他们认为所有字符加起来顶多 100 多个,只要 1 字节(8 位,支持 256 个字符编号)即可为所有字符编号一一这就是 ASCII 字符集

    后来各个国家都为本国文字进行编码,为了解决兼容问题,使用了2个字节(16位,65536个字符编码)的字符集--Unicode字符集。实际使用的 UTF-8, UTF-16 等其实都属于 Unicode 字符集。


  • 相关阅读:
    Overloaded的方法是否可以改变返回值的类型
    parseXXX的用法
    java的类型转换问题。int a = 123456;short b = (short)a;System.out.println(b);为什么结果是-7616?
    UVA 10405 Longest Common Subsequence(简单DP)
    POJ 1001 Exponentiation(大数处理)
    POJ 2318 TOYS(计算几何)(二分)
    POJ 1265 Area (计算几何)(Pick定理)
    POJ 3371 Flesch Reading Ease (模拟题)
    POJ 3687 Labeling Balls(拓扑序列)
    POJ 1094 Sorting It All Out(拓扑序列)
  • 原文地址:https://www.cnblogs.com/chentianwei/p/11921394.html
Copyright © 2011-2022 走看看