开发者社区> 问答> 正文

python中进制表示什么

python中进制表示什么

展开
收起
云计算小粉 2018-05-10 20:11:04 1885 0
2 条回答
写回答
取消 提交回答
  • 你理解中的进制

    我们平时都是10进制

    计算机处理是用的二进制。 即01代码。

    还有16,8等进制

    2019-11-26 09:00:09
    赞同 展开评论 打赏
  • <0x00> 前言

    处理二进制文件或者从网络接收字节流时,字节流中的结构化数据可能存在二进制有符号数。虽然开发者根据字节流协议可以先验的知道有符号数的字节序、字长、符号位等信息,但在使用Python进行类型转换时缺少将这些信息显式传递给Python解释器的手段。本文介绍了两种在Python开发中处理二进制有符号数的方法。
    <0x01> Python如何处理数字类型

    很多编程语言在处理有符号数时将数字的最高位作为符号位,但Python的数字类型实现有所不同。以下是CPython中对长整形的定义:(以下皆为Python 2.7版本)
    include/longobject.h
    [cpp] view plain copy
    / Long (arbitrary precision) integer object interface /

    typedef struct _longobject PyLongObject; / Revealed in longintrepr.h /

    include/longintrepr.h
    [cpp] view plain copy
    /* Long integer representation.
    The absolute value of a number is equal to

    SUM(for i=0 through abs(ob_size)-1) ob_digit[i] * 2**(SHIFT*i) 

    Negative numbers are represented with ob_size < 0;
    zero is represented by ob_size == 0.
    In a normalized number, ob_digit[abs(ob_size)-1](the most significant
    digit) is never zero. Also, in all cases, for all valid i,

    0 <= ob_digit[i] <= MASK. 

    The allocation function takes care of allocating extra memory
    so that ob_digit[0] ... ob_digit[abs(ob_size)-1] are actually available.

    CAUTION: Generic code manipulating subtypes of PyVarObject has to
    aware that longs abuse ob_size's sign bit.
    */

    struct _longobject {

    PyObject_VAR_HEAD  
    digit ob_digit[1];  

    };

    include/object.h
    [cpp] view plain copy
    /* PyObject_VAR_HEAD defines the initial segment of all variable-size

    • container objects. These end with a declaration of an array with 1
    • element, but enough space is malloc'ed so that the array actually
    • has room for ob_size elements. Note that ob_size is an element count,
    • not necessarily a byte count.
      */

    define PyObject_VAR_HEAD \

    PyObject_HEAD                       \  
    Py_ssize_t ob_size; /* Number of items in variable part */  
    

    从以上代码以及注释中我们知道,Python中的长整形,即_longobject,其符号位是通过PyObject_VAR_HEAD中的ob_size来表示,而ob_digit只存储着长整形的绝对值。
    另一方面,当我们初始化一个长整形对象(即将一个数值赋值给对象)的时候,Python解释器并不会把这个数值的最高位当作符号位而是将其当作有效位。
    下面以数值-500为例,来看看使用该数值对Python对象赋值会发生什么,简便起见,这里使用16bit字长。
    我们知道,为了计算方便,负数在计算机中以其二进制补码形式存储,我们首先将-500转换为二进制补码:
    十进制 -500
    十六进制 -0x01 F4
    二进制 -0b 0000 0001 1111 0100
    二进制原码(符号在最高位) 0b 1000 0001 1111 0100
    二进制反码(除符号位外,对原码按位取反) 0b 1111 1110 0000 1011
    二进制补码(二进制反码加1) 0b 1111 1110 0000 1100
    二进制补码的十六进制表示 0xFE 0C
    下面代码模拟从字节流中接收到一个大字节序的二进制串(0xFE 0x0C)并把它赋值给一个Python变量然后打印该变量的值:
    [python] view plain copy

    stream = 'xFEx0C'
    number = (ord(stream[0]) << 8) + ord(stream[1])
    '0x{:0X}'.format(number)

    '0xFE0C'

    print number

    65036

    这显然不是我们想要的结果,为了让Python在以有符号数对对象进行初始化时正确工作,上面的代码需要修改。
    <0x02> 使用负号传递数值的符号信息

    现在我们知道Python并不从数字的符号位读取符号信息,为了让Python正确的处理该数值,开发者必须显示的通知Python解释器:这是一个负数。开发者可以借助负号(-),即negative操作符来完成这个任务。
    先看一下negtive操作符在CPython中的实现:
    Objects/longobject.c
    [cpp] view plain copy
    static PyObject *
    long_neg(PyLongObject *v)
    {

    PyLongObject *z;  
    if (v->ob_size == 0 && PyLong_CheckExact(v)) {  
        /* -0 == 0 */  
        Py_INCREF(v);  
        return (PyObject *) v;  
    }  
    z = (PyLongObject *)_PyLong_Copy(v);  
    if (z != NULL)  
        z->ob_size = -(v->ob_size);  
    return (PyObject *)z;  

    }

    可见negtive操作符只对_longobject的ob_size域(即Python记载的符号位)进行了negtive操作,而ob_digit域不变。
    我们还知道,如果数值value为负数,则有value = - abs(value)。当我们将负数的绝对值和negtive操作符一起传递给Python解释器,Python解释器就能正确的处理该数值。
    对于本例中的二进制串0xFE 0x0C,我们已经先验的知道了该串的字节序,字长信息,所以其符号位在最高位即bit15。因符号位为1,则该数值为负数。下一步是对该数值求绝对值,由于数值是二进制补码形式存储,则其绝对值为二进制补码减去1(即其二进制反码)再按位取反。
    代码如下:
    [python] view plain copy

    number = 0xFE0C
    if (number & 0x8000) != 0:
    ... number = -((number - 1) ^ 0xFFFF)

    ...

    print number

    -500

    细心的读者可能会注意到上面代码中按位取反操作并没有使用~(即invert操作符),而是使用的和0xFFFF异或来实现。
    如果改为invert操作符会如何呢?
    [python] view plain copy

    number = 0xFE0C
    if (number & 0x8000) != 0:

    ... number = -(~(number - 1))
    ...

    print number

    65036

    还是让我们来看一下CPython对invert操作符的实现:
    Objects/longobject.c
    [cpp] view plain copy
    static PyObject *
    long_invert(PyLongObject *v)
    {

    /* Implement ~x as -(x+1) */  
    PyLongObject *x;  
    PyLongObject *w;  
    w = (PyLongObject *)PyLong_FromLong(1L);  
    if (w == NULL)  
        return NULL;  
    x = (PyLongObject *) long_add(v, w);  
    Py_DECREF(w);  
    if (x == NULL)  
        return NULL;  
    Py_SIZE(x) = -(Py_SIZE(x));  
    return (PyObject *)x;  

    }
    正如代码中的注释说明,Python的invert操作符的实现并不是真的按位取反,而是对数值加1后的negtive操作。

    <0x03> 一个更通用的库

    struct是一个对二进制结构化数据解包与打包的库,可以让你使用对开发者更友好的方式来传递字节序、字长、符号位等信息,同时也有着足够的错误报告机制,让你的开发更高效。
    [python] view plain copy

    import struct
    stream = 'xFEx0C'
    number, = struct.unpack('>h', stream)
    print number
    -500

    '>h'是struct支持的格式化串,‘>'表明字节流为大字节序,‘h'表明字节流包含signed short。关于struct模块更多的说明可参见这个链接。

    2019-07-17 22:25:09
    赞同 展开评论 打赏
问答分类:
问答地址:
问答排行榜
最热
最新

相关电子书

更多
From Python Scikit-Learn to Sc 立即下载
Data Pre-Processing in Python: 立即下载
双剑合璧-Python和大数据计算平台的结合 立即下载