C 确定数字是否可以表示为n位整数(两个&x27;s补码)
关于二的补码,我有点难以理解如何使用C中的位 这是家庭作业的一部分,但我不是在寻找代码答案,而是想了解2的补码表示法是怎么回事 我的任务是将一个数字限制在一定数量的位(n)内,并确定给定的数字是否可以用n个位的2的补码表示 根据示例,5不能表示为3位整数,而-4可以表示为3位整数 为什么会这样C 确定数字是否可以表示为n位整数(两个&x27;s补码),c,bit-manipulation,C,Bit Manipulation,关于二的补码,我有点难以理解如何使用C中的位 这是家庭作业的一部分,但我不是在寻找代码答案,而是想了解2的补码表示法是怎么回事 我的任务是将一个数字限制在一定数量的位(n)内,并确定给定的数字是否可以用n个位的2的补码表示 根据示例,5不能表示为3位整数,而-4可以表示为3位整数 为什么会这样 编辑:我对我的思维过程做了详细的解释,但意识到我完全错了,所以决定省略它 我最初的推理是看允许5和-5、4和-4用3位表示是否有意义。但这没有道理,因为这并不能真正解决问题 我理解5和-4如何表示为2的
编辑:我对我的思维过程做了详细的解释,但意识到我完全错了,所以决定省略它 我最初的推理是看允许5和-5、4和-4用3位表示是否有意义。但这没有道理,因为这并不能真正解决问题 我理解5和-4如何表示为2的补码。例如,作为4位: 5:0101 -4:1100
第二次编辑: 为了澄清,决定添加我的原始推理: 5是0101,-5是1011。
我可以看出,当限制为3位时,5不能用2的补码表示,因为如果没有第4位,我们就不能表示-5是负数。我们需要1011的额外1。如果我们最多只能有3位,那么我们就有011位,并且没有办法区分-5和3位,后者是0011分4位,011分3位。 这个推理正确吗 4是0100,-4是1100。
在这里我很困惑。我不明白为什么-4可以用3位表示为2的补码整数 4表示为0100,100表示为3位。 -4是,如果我们从4(100)开始,我们翻转100(011),再加上1(100),我们又剩下了100(3位)。在4位中,我相信这表示为1100
我的困惑是,我们不需要额外的1,对于1100,来区分-4和4,也就是0100吗?如果我们只有3位,那么我们如何区分100和100呢?为了理解这一点,请记住,尽管在现代硬件中普遍存在,但2的补码不是自然法则,而是人类构造 假设我们想把一个整数压缩成n位。为了简单和简洁,设n=3。显然,只要我们是一致的,我们可以选择任何23=8的整数,但有些选择在算术方面比其他选择更容易 无符号整数是直接向前的。有一个自然映射:
Encoding Value
000 0
001 1
010 2
011 3
100 4
101 5
110 6
111 7
这只是值的二进制编码,带有零填充。零的所有位都是零,这很方便。加减法只起作用,模为2n
有符号整数更复杂。在普遍采用两个补码之前,至少还使用了另外两种表示法:符号幅度(SM)和一个补码(1C)
SM和1C两种编码都使用n位来存储从-(2n-1-1)到2n-1-1的有符号整数。两种编码存储正整数的方式与以前相同。好:两者在正向和负向上的距离相同。好:这两种方法都可以使消极性测试变得容易(除了零,这通常需要特殊处理)。好:这两种方法都可以使数字求反变得简单(SM:翻转符号位;1C:翻转所有位)。坏:两者都包含一个不必要的“负零”,这使得等式测试和算术测试变得复杂
这就引出了2的补码(2C)
这里,我们先从正整数开始,然后从零开始计数“负”,直到我们在中间相遇。好:这使得算术非常自然,就像在无符号情况下一样简单。坏:否定比SM或1C更复杂
但我们该怎么处理这一排的?我们已经拥有1C和SM中的所有数字。我们可以选择4,或者-4,或者“未定义”。2C中的惯例是我们选择负值。这为我们提供了-4到+3的范围,或者更一般地说是-2n-1到2n-1-1。这种非对称范围很尴尬(我们有-4,但不是+4,事实证明-4是它自己的负数![1]),但保留了所有负数都有顶部位集的属性,并确保每个编码都有一个与之相关的值 所以(最后!)继续你的问题。为什么可以代表-4 在2的补码中作为3位整数?因为这是最不坏的选择 进一步阅读:在维基百科上[1] 这里有一个测试程序来演示这有多混乱。这里的
int
是32位宽
[~]% cat 2c.c
#include <stdio.h>
#include <limits.h>
int main(void) {
int i = INT_MAX;
int j = INT_MIN;
printf (" i = % d (hex %x)\n", i, i);
printf (" j = % d (hex %x)\n", j, j);
printf (" -i = % d (hex %x)\n", -i, -i);
printf (" -j = % d (hex %x)\n", -j, -j);
printf ("i*-1 = % d (hex %x)\n", i*-1, i*-1);
printf ("j*-1 = % d (hex %x)\n", j*-1, j*-1);
printf ("i/-1 = % d (hex %x)\n", i/-1, i/-1);
printf ("j/-1 = % d (hex %x)\n", j/-1, j/-1);
return 0;
}
这是一个原因(遗憾的是,大多数真实的人没有得到有趣的演练)。为了理解这一点,请记住,尽管二者互补在现代硬件上无处不在,但它不是自然法则,而是人类构造 假设我们想把一个整数压缩成n位。为了简单和简洁,设n=3。显然,只要我们是一致的,我们可以选择任何23=8的整数,但有些选择在算术方面比其他选择更容易 无符号整数是直接向前的。有一个自然映射:
Encoding Value
000 0
001 1
010 2
011 3
100 4
101 5
110 6
111 7
这只是值的二进制编码,带有零填充。零的所有位都是零,这很方便。加减法只起作用,模为2n
有符号整数更复杂。在普遍采用两个补码之前,至少还使用了另外两种表示法:符号幅度(SM)和一个补码(1C)
SM和1C两种编码都使用n位来存储从-(2n-1-1)到2n-1-1的有符号整数。两种编码存储正整数的方式与以前相同。好:两者在正向和负向上的距离相同。好:这两种方法都可以使消极性测试变得容易(除了零,这通常需要特殊处理)。好的:机器人
[~]% cat 2c.c
#include <stdio.h>
#include <limits.h>
int main(void) {
int i = INT_MAX;
int j = INT_MIN;
printf (" i = % d (hex %x)\n", i, i);
printf (" j = % d (hex %x)\n", j, j);
printf (" -i = % d (hex %x)\n", -i, -i);
printf (" -j = % d (hex %x)\n", -j, -j);
printf ("i*-1 = % d (hex %x)\n", i*-1, i*-1);
printf ("j*-1 = % d (hex %x)\n", j*-1, j*-1);
printf ("i/-1 = % d (hex %x)\n", i/-1, i/-1);
printf ("j/-1 = % d (hex %x)\n", j/-1, j/-1);
return 0;
}
[~]% clang -Wall 2c.c -o 2c && ./2c
i = 2147483647 (hex 7fffffff)
j = -2147483648 (hex 80000000)
-i = -2147483647 (hex 80000001)
-j = -2147483648 (hex 80000000)
i*-1 = -2147483647 (hex 80000001)
j*-1 = -2147483648 (hex 80000000)
i/-1 = -2147483647 (hex 80000001)
zsh: floating point exception ./2c