我听说 C、C++、Java 使用两个补码来表示二进制。为什么不使用 1 补码?使用 2 补码超过 1 补码有什么优势吗?
8 回答
使用二进制补码有符号整数要干净得多。您基本上可以添加带符号的值,就好像它们是无符号的一样,并让事情按您预期的那样工作,而不必显式地处理额外的进位添加。检查一个值是否为 0 也更容易,因为二进制补码只包含一个 0 值,而一个补码允许一个定义正零和负零。
至于额外的进位加法,请考虑将一个正数加到一个较小的负数上。由于一个的补码表示,当被视为无符号数量时,较小的负数实际上会相当大。将两者相加可能会导致进位溢出。与无符号加法不同,这并不一定意味着该值太大而无法在一个补码中表示,只是表示暂时超过了可用的位数。为了弥补这一点,您可以在将两个补码数字相加后添加进位位。
数字的内部表示不是任何这些语言的一部分,它是机器本身架构的一个特征。大多数实现都使用 2 的补码,因为它使加法和减法成为相同的二进制运算(有符号和无符号运算是相同的)。
这是一个家庭作业问题吗?如果是这样,请考虑如何在 1 的补码系统中表示 0。
对于不同的语言,答案是不同的。
在 C 的情况下,理论上你可以在1 的补码机器上实现该语言……如果你仍然可以找到一个工作的 1 的补码机器来运行你的程序!使用 1 的补码会引入可移植性问题,但这是 C 语言的常态。我不确定 C++ 的情况如何,但如果相同,我不会感到惊讶。
对于 Java,语言规范规定了基本类型的精确大小和表示,以及算术运算符的精确行为。这样做是为了消除当您使这些东西实现特定时出现的可移植性问题。Java 设计者指定了 2 的补码算法,因为所有现代 CPU 架构都实现了 2 的补码,而不是 1 的补码整数。
对于现代硬件实现 2 的补码而不是 1 的补码的原因,请查看(例如)有关该主题的 Wikipedia 页面。看看你是否能弄清楚替代方案的含义。
至少 C 和 C++ 通过语言的~
运算符提供 1 的补码否定(与按位否定相同)。大多数处理器 - 以及所有现代处理器 - 使用 2 的补码表示有几个原因:
- 添加正数和负数与添加无符号整数相同
- 由于 0 的两种表示形式(+0 和 -0),没有“浪费”值
编辑: C ++0x 草案没有指定有符号整数类型是 1 的补码还是 2 的补码,这意味着 C 和 C++ 的早期版本不太可能指定它。您观察到的是实现定义的行为,出于性能原因,它至少在现代处理器上是 2 的补码。
几乎所有现有的 CPU 硬件都使用二进制补码,因此大多数编程语言也这样做是有道理的。
如果硬件提供,C 和 C++ 支持补码。
它与零和舍入有关。如果你使用第一个补码,你最终可能会有两个零。请参阅此处了解更多信息。
对于数字代码,符号幅度表示会好得多。缺乏对称性是 2 的补码的一个真正问题,并且也排除了许多有用的(面向数字的)位黑客。2 的补码还引入了算术运算可能无法为您提供您认为可能的结果的技巧情况。所以你必须注意区分、转移和否定。