2022年 11月 5日

python负数的表示方法_负整数的Python表示

CPython integer类型将符号存储在结构的特定字段中。当执行按位运算时,CPython用两个补码替换负数,有时(!)执行相反的运算(即用负数替换两个补码)。在

按位运算

整数的内部表示是PyLongObject结构,它包含PyVarObject结构。(当CPython创建一个新的PyLong对象时,它为结构分配内存,并为数字分配一个尾随空格。)这里重要的是PyLong的大小是:PyVarObject嵌入结构的ob_size字段包含整数的大小(以数字为单位)(数字可以是15位或30位数字)。

如果整数为负数,则该大小为减去位数。在

如您所见,内部CPython对整数的表示方式与通常的二进制表示方式相差甚远。然而CPython必须为各种目的提供位操作。让我们看看the code中的注释:static PyObject *

long_bitwise(PyLongObject *a,

char op, /* ‘&’, ‘|’, ‘^’ */

PyLongObject *b)

{

/* Bitwise operations for negative numbers operate as though

on a two’s complement representation. So convert arguments

from sign-magnitude to two’s complement, and convert the

result back to sign-magnitude at the end. */

/* If a is negative, replace it by its two’s complement. */

/* Same for b. */

/* Complement result if negative. */

}

为了在按位运算中处理负整数,CPython使用2的补码(实际上,这是一个2的补码,但我不详细讨论)。但请注意“符号规则”(名字是我的):结果的符号是应用于数字符号的位运算符。更准确地说,如果nega negb == 1,negx=1表示阴性,0表示阳性)。Simplified code:

^{pr2}$

二进制格式

另一方面,格式化程序不执行二者的补码,即使是在二进制表示中:[format_long_internal](https://github.com/python/cpython/blob/master/Python/formatter_unicode.c#L839)调用[long_format_binary](https://github.com/python/cpython/blob/master/Objects/longobject.c#L1934)并删除两个前导字符,但保留符号。见the code:/* Is a sign character present in the output? If so, remember it

and skip it */

if (PyUnicode_READ_CHAR(tmp, inumeric_chars) == ‘-‘) {

sign_char = ‘-‘;

++prefix;

++leading_chars_to_skip;

}

long_format_binary函数不执行任何2的补码:只输出以2为基数的数字,preceeded by the sign。在if (negative) \

* p = ‘-‘; \

你的问题

我会按照你的回复顺序:>>> x = -4

>>> print(“{} {:b}”.format(x, x))

-4 -100

没什么奇怪的,因为格式中没有二的补码,只有一个符号。在>>> mask = 0xFFFFFFFF

>>> print(“{} {:b}”.format(x & mask, x & mask))

4294967292 11111111111111111111111111111100

数字-4为负数。因此,它被逻辑“与”之前的“二”补码替换,一位数接一位数。你本以为结果会变成负数,但请记住“符号规则”:>>> nega=1; negb=0

>>> nega & negb

0

因此:1。结果没有负号。结果不是两个结果的补充。你的结果符合“符号规则”,即使这个规则看起来不是很直观。在

现在,最后一部分:>>> x = 0b11111111111111111111111111111100

>>> print(“{} {:b}”.format(x, x))

4294967292 11111111111111111111111111111100

>>> print(“{} {:b}”.format(~(x ^ mask), ~(x ^ mask)))

-4 -100

同样,-4是负的,因此被它的两个补码0b11111111111111111111111111111100替换,然后用0b11111111111111111111111111111111进行异或。结果是0b11(3)。你取一元补码,也就是0b11111111111111111111111111111100,但这次符号是负数:>>> nega=1; negb=0

>>> nega ^ negb

1

因此,正如您所期望的,结果是补的并得到负号。在

结论:我想没有一个完美的解决方案可以让任意长符号数和提供按位操作,但文档中并没有对所做选择进行详细说明。在