我只是好奇,为了在二进制中表示-1,是否有一个原因,使用了2的补码:翻转位并加1?

-1由11111111(2的补码)表示,而不是(对我来说更直观)10000001,10000001是二进制1,第一位为负标志。

免责声明:我的工作不依赖二进制算术!


当前回答

我有一个在某些情况下很重要的小补充:在这些限制条件下,2的恭维是唯一可能的表示:

无符号数和二的补数是恒等交换环。它们之间有一个同态。 它们共享相同的表示,对负数有不同的分支切割,(因此,为什么它们之间的加法和乘法是相同的)。 高位决定符号。

要知道为什么,它有助于降低基数;例如Z_4。

星座、星等和一个人的赞美都不能形成一个具有相同数量元素的环;一个症状是双零。因此,很难在边缘上工作;为了在数学上保持一致,它们需要检查溢出或陷阱表示。

其他回答

在阅读这个问题的答案时,我看到了这条评论[编辑]。

0100(4)的补数是1100。现在1100是12如果我说正常的话。所以, 当我说标准1100时,它是12,但当我说2的补足1100时,那么 是-4?另外,在Java中,当1100(假设现在是4位)被存储时 如何确定它是+12还是-4 ?——hagrawal 7月2日16:53

在我看来,这条评论中提出的问题非常有趣,所以我想首先重新措辞,然后提供一个答案和一个例子。

系统如何确定一个或多个相邻字节必须如何解释?特别是,系统如何确定给定的字节序列是普通二进制数还是2的补数?

ANSWER -系统建立如何通过类型解释字节序列。 类型定义

需要考虑多少字节 如何解释这些字节

示例-下面我们假设

Char的长度为1字节 短的是2字节长 Int型和float型的长度是4字节

请注意,这些大小是特定于我的系统的。尽管非常常见,但它们可能因系统而异。如果您想知道它们在您的系统中是什么,请使用sizeof操作符。

首先,我们定义一个包含4个字节的数组,并将它们初始化为二进制数10111101,对应于十六进制数BD。

// BD(hexadecimal) = 10111101 (binary)
unsigned char   l_Just4Bytes[ 4 ]   =   { 0xBD, 0xBD, 0xBD, 0xBD };

然后我们使用不同的类型读取数组内容。

Unsigned char和signed char

// 10111101 as a PLAIN BINARY number equals 189
printf( "l_Just4Bytes as unsigned char  -> %hi\n", *( ( unsigned char* )l_Just4Bytes ) );

// 10111101 as a 2'S COMPLEMENT number equals -67
printf( "l_Just4Bytes as signed char    -> %i\n", *( ( signed char* )l_Just4Bytes ) );

未签名的空头和空头

// 1011110110111101 as a PLAIN BINARY number equals 48573
printf( "l_Just4Bytes as unsigned short -> %hu\n", *( ( unsigned short* )l_Just4Bytes ) );

// 1011110110111101 as a 2'S COMPLEMENT number equals -16963
printf( "l_Just4Bytes as short          -> %hi\n", *( ( short* )l_Just4Bytes ) );

Unsigned int, int和float

// 10111101101111011011110110111101 as a PLAIN BINARY number equals 3183328701
printf( "l_Just4Bytes as unsigned int   -> %u\n", *( ( unsigned int* )l_Just4Bytes ) );

// 10111101101111011011110110111101 as a 2'S COMPLEMENT number equals -1111638595
printf( "l_Just4Bytes as int            -> %i\n", *( ( int* )l_Just4Bytes ) );

// 10111101101111011011110110111101 as a IEEE 754 SINGLE-PRECISION number equals -0.092647
printf( "l_Just4Bytes as float          -> %f\n", *( ( float* )l_Just4Bytes ) );

内存中的4个字节(l_Just4Bytes[0..]3)始终保持完全相同。唯一改变的是我们如何理解它们。

同样,我们告诉系统如何通过类型来解释它们。

例如,上面我们使用了以下类型来解释l_Just4Bytes数组的内容

无符号字符:纯二进制的1字节 有符号字符:2的补码中的1字节 无符号短:2字节的纯二进制表示法 短:2字节的2补码 Unsigned int: 4字节的纯二进制表示法 Int: 4字节的2的补码 float:在IEEE 754单精度表示法中为4字节


[编辑]这篇文章是在user4581301的评论后编辑的。谢谢你抽出时间来写这些有用的句子!

尽管这个问题已经很老了,但还是让我说说我的看法。

在我解释这个之前,让我们回到基础上来。2'补码等于1'补码+ 1。 那么1的补是什么,它的加法意义是什么。

任何n位数和它的1的补数的和给出了可以用这n位表示的最大可能的数。 例子:

 0010 (2 in 4 bit system)
+1101 (1's complement of 2)
___________________________
 1111  (the highest number that we can represent by 4 bits)

现在如果我们尝试在结果中再加1会发生什么。这将导致溢出。

结果将是1 000,即0(因为我们处理的是4位数字,(左边的1是溢出)

So ,

Any n-bit number + its 1's complement = max n-bit number
Any n-bit number + its 1'complement + 1 = 0 ( as explained above, overflow will occur as we are adding 1 to max n-bit number)

于是有人决定把1的补体+ 1称为2'补体。所以上面的表述变成: 任何n位数+它的2的补= 0 也就是说2对一个数的补= -(该数的补)

所有这一切又产生了一个问题,为什么我们只能使用n位中的(n-1)来表示正数,为什么最左边的第n位表示符号(最左边的0表示+ve个数字,1表示-ve个数字)。例如,为什么我们在Java中只使用int的前31位来表示正数,如果第32位是1,它是-ve数。

 1100 (lets assume 12 in 4 bit system)
+0100(2's complement of 12)
___________________________

1 0000(结果为0,进位1溢出)

因此(n + 2'补n) = 0的方程组仍然成立。这里唯一的歧义是2对12的补码是0100,它也模糊地表示+8,而不是在2s补码系统中表示-12。

如果正数的最左边总是有一个0,这个问题就可以解决了。在这种情况下,它们的2的补位总是在最左边有一个1,我们就不会有相同的位集表示2的补位数和+ve数的模糊性。

为什么用Two2的补语系统来表示负数,而不是用One的补语系统,一个令人满意的答案是 二的补语系统解决了一的补语系统中存在的表示负数的0的多重表示和对进位的需要。

欲了解更多信息,请访问https://en.wikipedia.org/wiki/Signed_number_representations

用于末端绕行访问 https://en.wikipedia.org/wiki/End-around_carry

2的补语允许负数和正数相加,而不需要任何特殊的逻辑。

如果你想用你的方法做1和-1相加 10000001 (1) + 00000001 (1) 你得到 10000010 (2)

相反,通过使用2的补数,我们可以相加

11111111 (1) + 00000001 (1) 你得到 00000000 (0)

减法也是如此。

同样,如果你试着用6减去4(两个正数),你可以用2补4,然后把两者相加6 + (-4)= 6 -4 = 2

这意味着正数和负数的减法和加法都可以由cpu中的同一个电路完成。

我们对加减法都只做加法运算。我们将第二个操作数与第一个操作数相加。对于减法,我们将第二个操作数的2的补数与第一个操作数相加。

对于2的补码表示,我们不需要单独的数字组件,只使用加法器和补法器。