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 0000 ,这是0(因为我们使用4位数字,(左边的1是溢出)
所以,
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)
// 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 ) );
unsigned short and short
// 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 ) );
这里提到的两个's-complement representation which hasn't的主要优点是二进制补码和,差或乘积的低位仅取决于操作数的相应位 . -1的8位有符号值是 11111111 的原因是从最低8位为 0000000 的任何其他整数中减去最低8位为 00000001 的任何整数将产生最低8位为 11111111 的整数 . 在数学上,值-1将是1 's, but all values within the range of a particular integer type will either be all 1' s的无限字符串或者所有0 's past a certain point, so it' s便于计算机"sign-extend"数字的最高位,就像它表示无限数量的1 's or 0' s一样 .
一个令人满意的答案为什么Two2 's Complement is used to represent negative numbers rather than One' s补语系统是两个补语系统解决 multiple representations of 0 的问题,并且需要 end-around-carry 存在于表示负数的一元补充系统中 .
18 回答
它's done so that addition doesn'需要有任何特殊的逻辑来处理负数 . 看看the article on Wikipedia .
假设你有两个数字,2和-1 . 在"intuitive"表示数字的方式中,它们分别是
0010
和1001
(我是'm sticking to 4 bits for size). In the two'的补充方式,它们是0010
和1111
. 现在,假设我想添加它们 .两个补码的添加非常简单 . 您正常添加数字,最后的任何进位都被丢弃 . 所以他们添加如下:
0001
是1,这是"2+(-1)"的预期结果 .但在你的“直观”方法中,添加更复杂:
哪个是-3,对吗?在这种情况下,简单的添加不起作用 . 您需要注意其中一个数字是否定的,如果是这种情况则使用不同的算法 .
对于这种“直观”存储方法,减法是与添加不同的操作,需要在添加之前对数字进行额外检查 . 由于您希望最基本的操作(加法,减法等)尽可能快,因此您需要以允许您使用最简单算法的方式存储数字 .
此外,在“直观”存储方法中,有两个零:
这些数字直观相同,但在存储时具有两个不同的值 . 每个应用程序都需要采取额外的步骤来确保非零值也不是负零 .
以这种方式存储整数还有另外一个好处,那就是当你需要扩展寄存器的宽度时,存储的值 . 使用二进制补码,将一个4位数存储在一个8位寄存器中是一个重复的问题 . 最重要的一点:
这只是查看较小单词的符号位并重复它直到它填充较大单词的宽度的问题 .
使用您的方法,您需要清除现有位,这是一个额外的操作,除了填充:
在这两种情况下,您仍然需要设置额外的4位,但在“直观”的情况下,您还需要清除第5位 . 在每个应用程序中最基本和最常见的操作之一中,这是一个微小的额外步骤 .
Wikipedia说了一切:
换句话说,添加是相同的,无论数字是否为负数 .
即使这个问题已经过时了,让我加入我的2美分 .
在我解释之前,让我们回到基础 . 2'补码是1的补码1 . 现在什么是1的补充,另外还有什么意义 .
任何n位数及其1的补码之和为您提供可由这些n位表示的最高数字 . 例:
现在,如果我们尝试在结果中再添加1个,会发生什么 . 它会导致溢出 .
结果将是
1 0000
,这是0(因为我们使用4位数字,(左边的1是溢出)所以,
然后有人决定将1的补码1称为2'补码 . 所以上面的陈述变成:任何n位数,其2的补码= 0,这意味着2的补数= - (该数字)
所有这些产生了另一个问题,为什么我们只能使用n位中的(n-1)来表示正数,为什么最左边的第n位代表符号(最左边的位表示ve数,1表示 - ve号) . 例如,为什么我们只使用java中int的前31位表示正数,如果第32位为1,则为-ve数 .
1 0000(结果为零,进位1溢出)
因此,(n 2'的实现)n = 0的系统仍然有效 . 这里唯一的歧义是2的12的补码是0100,它除了在2s补码系统中代表-12之外,它也模糊地代表8 .
如果正数在其最左边的位中始终为0,则将解决此问题 . 在那种情况下,它们的2的补码在它们的最左位总是有1,并且我们不会有同一组位的模糊性,表示2的补码数和ve数 .
Two's complement允许以正常方式进行加法和减法(就像你为无符号数字缠绕一样) . 它还可以防止-0(用一种比较数字的正常逐位方法表示0不会等于0的单独方式) .
这是为了简化数字的总和和差异 . 在2的补语中编码的负数和正数之和与以正常方式对它们求和相同 .
该操作的通常实现是“翻转位并添加1”,但还有另一种定义它的方法可能使基本原理更清晰 . 2的补码是你得到的形式,如果你采用通常的无符号表示,其中每个位控制下一个2的幂,并且只使最重要的项为负 .
取8位值a7 a6 a5 a4 a3 a2 a1 a0
通常的无符号二进制解释是:
27 * a7 26 * a6 25 * a5 24 * a4 23 * a3 22 * a2 21 * a1 20 * a0
11111111 = 128 64 32 16 8 4 2 1 = 255
这两个补语的解释是:
-27 * a7 26 * a6 25 * a5 24 * a4 23 * a3 22 * a2 21 * a1 20 * a0
11111111 = -128 64 32 16 8 4 2 1 = -1
其他任何一个位都没有改变意义,并且进入a7是"overflow"并且预计不会起作用,因此几乎所有的算术运算都可以不加修改地工作(正如其他人已经注意到的那样) . 符号幅度通常检查符号位并使用不同的逻辑 .
要扩展其他答案:
在二的补充
添加与普通正整数添加的机制相同 .
减法也不会改变
乘法也是!
分部确实需要不同的机制 .
所有这些都是正确的,因为两个补码只是正常的模运算,我们选择通过减去模数来看一些数字为负数 .
二进制补码允许将负数和正数加在一起,而无需任何特殊逻辑 .
如果您尝试使用您的方法添加1和-1
10000001(-1)
00000001(1)
你得到
10000010(-2)
相反,通过使用两个补码,我们可以添加
11111111(-1)
00000001(1)你明白了
00000000(0)
减法也是如此 .
此外,如果你试图从6减去4(两个正数)你可以2补4并将两个加在一起6(-4)= 6 - 4 = 2
这意味着正负数的减法和加法都可以由cpu中的相同电路完成 .
阅读这个问题的答案,我发现了这个评论[编辑] .
在我看来,这个评论中提到的问题非常有趣,所以我首先想要改写它然后提供答案和一个例子 .
问题 - 系统如何确定如何解释一个或多个相邻字节?特别是,系统如何确定给定的字节序列是纯二进制数还是2的补数?
解答 - 系统 Build 如何通过类型解释字节序列 . 类型定义
必须考虑多少字节
必须如何解释这些字节
示例 - 下面我们假设
char
的长度为1个字节short
的长度为2个字节int
和float
的长度为4个字节请注意,这些尺寸特定于我的系统 . 虽然很常见,但它们可能因系统而异 . 如果您对系统中的内容感到好奇,请使用sizeof operator .
首先,我们定义一个包含4个字节的数组,并将它们全部初始化为二进制数
10111101
,对应于十六进制数BD
.然后我们使用不同的类型读取数组内容 .
unsigned char和signed char
unsigned short and short
unsigned int,int和float
RAM中的4个字节(
l_Just4Bytes[ 0..3 ]
)始终保持完全相同 . 唯一改变的是我们如何解释它们 .同样,我们告诉系统如何通过类型解释它们 .
例如,上面我们使用以下类型来解释
l_Just4Bytes
数组的内容unsigned char
:普通二进制文件中的1个字节signed char
:2的补码中有1个字节unsigned short
:普通二进制表示法中的2个字节short
:2的补码中有2个字节unsigned int
:普通二进制表示法中的4个字节int
:2的补码中有4个字节float
:IEEE 754单精度表示法中的4个字节[编辑]此帖子已在用户4581301发表评论后进行了编辑 . 感谢您抽出宝贵时间放弃这几条有用的线路!
您可以观看斯坦福大学的杰里·凯恩教授,在斯坦福大学可以观看的编程范例系列讲座中解释两个's complement, in the second lecture (the explanation regarding the 2'补充从13:00左右开始补充's YouTube channel. Here' s讲座系列的链接:http://www.youtube.com/view_play_list?p=9D558D49CA734A02 .
使用二进制补码是因为它在电路中实现起来更简单,并且也不允许负零 .
如果有x位,则二进制补码的范围为(2 ^ x / 2 1)到 - (2 ^ x / 2) . 一个补码将从(2 ^ x / 2)运行到 - (2 ^ x / 2),但允许负零(0000在4位1的补码系统中等于1000) .
那么,你的意图并不是要反转二进制数的所有位 . 它实际上是从1中减去每个数字 . 这只是一个幸运的巧合,从1中减去1导致0并从1中减去0导致1.所以翻转位实际上是执行这个减法 .
但为什么你发现每个数字与1的差异?好吧,你不是 . 您的实际意图是计算给定二进制数与另一个二进制数的差异,该二进制数具有相同的位数但仅包含1 . 例如,如果您的数字是10110001,当您翻转所有这些位时,您就会有效地计算(11111111 - 10110001) .
这解释了计算Two's补语的第一步 . 现在让我们在图片中包括第二步 - 添加1 - .
在上面的二元方程中加1:
11111111 - 10110001 1
你得到了什么?这个:
100000000 - 10110001
这是最后的等式 . 通过执行这两个步骤,你试图找到这个,最后的差异:二进制数从另一个二进制数中减去一个额外的数字并包含零,除了在最具意义的位位置 .
但是为什么我们真的在这个差异之后呢?好吧,从这里开始,我想如果你阅读Wikipedia article会更好 .
我们只对加法和减法执行加法运算 . 我们将第二个操作数添加到第一个操作数以进行添加 . 对于减法,我们将第二个操作数的2的补码添加到第一个操作数 .
使用2的补码表示,我们不需要单独的数字组件用于仅减法加法器和补充器 .
值得注意的是,在一些早期的添加机器上,在数字计算机时代之前,通过让操作员在每个键上使用不同颜色的图例集输入值来执行减法(因此每个键将输入9减去要编号的数字)减去),然后按一个特殊按钮就会假定进行计算 . 因此,在六位数的机器上,要从值中减去1234,操作员将按下通常指示“998,765”的按键并按下按钮以将该值加1加到正在进行的计算中 . 二进制补码算术只是早期“十进制补码”算术的二进制等价 .
通过补码方法执行减法的优点是硬件减少
复杂性 . 不需要用于加法和减法的不同数字电路 . 加法和减法仅由加法器执行 .
这里提到的两个's-complement representation which hasn't的主要优点是二进制补码和,差或乘积的低位仅取决于操作数的相应位 . -1的8位有符号值是
11111111
的原因是从最低8位为0000000
的任何其他整数中减去最低8位为00000001
的任何整数将产生最低8位为11111111
的整数 . 在数学上,值-1将是1 's, but all values within the range of a particular integer type will either be all 1' s的无限字符串或者所有0 's past a certain point, so it' s便于计算机"sign-extend"数字的最高位,就像它表示无限数量的1 's or 0' s一样 .二进制补码只是在处理大于二进制机器的自然字大小的类型时唯一有效的有符号数表示,因为当执行加法或减法时,代码可以获取每个操作数的最低块,计算最低的块 . 结果,然后存储,然后加载每个操作数的下一个块,计算结果的下一个块,然后存储,等等 . 因此,即使是需要所有加法和减法的处理器都要通过一个8位寄存器可以合理有效地处理32位有符号数(当然,比32位寄存器慢,但仍然可行) .
当使用C标准允许的任何其他有符号表示时,结果的每一位都可能受到操作数的任何位的影响,因此必须立即在寄存器中保存整个值,或者使用额外的计算进行计算在至少某些情况下,需要读取,修改和重写结果的每个块的步骤 .
一个令人满意的答案为什么Two2 's Complement is used to represent negative numbers rather than One' s补语系统是两个补语系统解决 multiple representations of 0 的问题,并且需要 end-around-carry 存在于表示负数的一元补充系统中 .
有关更多信息,请访问https://en.wikipedia.org/wiki/Signed_number_representations
对于结束访问https://en.wikipedia.org/wiki/End-around_carry
因为CPU制造商很懒!