为什么C、C++、Java不使用补码?
我听说C、C++、Java使用两个补码来表示二进制。为什么不使用 1 补码?使用 2 个补体比使用 1 个补体有什么优势吗?
I heard C, C++, Java uses two complements for binary representation. Why not use 1 complement? Is there any advantage to use 2 complement over 1 complement?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(8)
使用二进制补码有符号整数要干净得多。您基本上可以添加有符号值,就好像它们是无符号的一样,并且让事情按照您的预期工作,而不必显式处理额外的进位加法。检查某个值是否为 0 也更容易,因为二进制补码仅包含一个 0 值,而二进制补码允许定义正零和负零。
至于额外进位加法,请考虑将一个正数与一个较小的负数相加。由于用补码表示,当将其视为无符号量时,较小的负数实际上会相当大。将两者相加可能会导致进位位溢出。与无符号加法不同,这并不一定意味着该值太大而无法用补码表示,只是表示暂时超出了可用位数。为了补偿这一点,您可以在将两个补码数相加后重新添加进位位。
Working with two's complement signed integers is a lot cleaner. You can basically add signed values as if they were unsigned and have things work as you might expect, rather than having to explicitly deal with an additional carry addition. It is also easier to check if a value is 0, because two's complement only contains one 0 value, whereas one's complement allows one to define both a positive and a negative zero.
As for the additional carry addition, think about adding a positive number to a smallish negative number. Because of the one's complement representation, the smallish negative number will actually be fairly large when viewed as an unsigned quantity. Adding the two together might lead to an overflow with a carry bit. Unlike unsigned addition, this doesn't necessarily mean that the value is too large to represent in the one's complement number, just that the representation temporarily exceeded the number of bits available. To compensate for this, you add the carry bit back in after adding the two one's complement numbers together.
数字的内部表示不是任何这些语言的一部分,它是机器本身架构的一个特征。大多数实现都使用 2 的补码,因为它使加法和减法成为相同的二进制运算(有符号和无符号运算相同)。
The internal representation of numbers is not part of any of those languages, it's a feature of the architecture of the machine itself. Most implementations use 2's complement because it makes addition and subtraction the same binary operation (signed and unsigned operations are identical).
这是家庭作业问题吗?如果是这样,请考虑如何在 1 的补码系统中表示 0。
Is this a homework question? If so, think of how you would represent 0 in a 1's complement system.
对于不同的语言,答案是不同的。
就 C 而言,理论上您可以在 1 的补码机器上实现该语言……如果您仍然可以找到可用的 1 的补码机器来运行您的程序!使用 1 的补码会引入可移植性问题,但这是 C 的规范。我不确定 C++ 的情况如何,但如果是相同的,我不会感到惊讶。
就 Java 而言,语言规范规定了基本类型的精确大小和表示形式,以及算术运算符的精确行为。这样做是为了消除当您使这些东西具体实现时出现的可移植性问题。 Java 设计者指定了 2 的补码算术,因为所有现代 CPU 架构都实现 2 的补码而不是 1 的补码整数。
要了解现代硬件实现 2 的补码而不是 1 的补码的原因,请查看(例如)有关该主题的 Wikipedia 页面。看看你是否能弄清楚替代方案的含义。
The answer is different for different languages.
In the case of C, you could in theory implement the language on a 1's complement machine ... if you could still find a working 1's complement machine to run your programs! Using 1's complement would introduce portability issues, but that's the norm for C. I'm not sure what the deal is for C++, but I wouldn't be surprised if it is the same.
In the case of Java, the language specification sets out precise sizes and representations for the primitive types, and precise behaviour for the arithmetic operators. This is done to eliminate the portability issues that arise when you make these things implementation specific. The Java designers specified 2's complement arithmetic because all modern CPU architectures implement 2's complement and not 1's complement integers.
For reasons why modern hardware implements 2's complement and not 1's complement, take a look at (for example) the Wikipedia pages on the subject. See if you can figure out the implications of the alternatives.
至少 C 和 C++ 通过语言的
~
运算符提供 1 的补码否定(与按位否定相同)。大多数处理器(以及所有现代处理器)都使用 2 的补码表示形式,原因如下:编辑: C++0x 草案 不指定有符号整数类型是 1 的补码还是 2 的补码,这意味着早期版本的 C 和 C++ 不太可能指定它。您观察到的是实现定义的行为,出于性能原因,它至少在现代处理器上是 2 的补码。
At least C and C++ offer 1's complement negation (which is the same as bitwise negation) via the language's
~
operator. Most processors - and all modern ones - use 2's complement representation for a couple reasons:Edit: The draft of C++0x does not specify whether signed integer types are 1's complement or 2's complement, which means it's highly unlikely that earlier versions of C and C++ did specify it. What you have observed is implementation-defined behavior, which is 2's complement on at least modern processors for performance reasons.
几乎所有现有的 CPU 硬件都使用二进制补码,因此大多数编程语言也这样做是有道理的。
C 和 C++ 支持补码(如果硬件提供)。
Almost all existing CPU hardware uses two's complement, so it makes sense that most programming languages do, too.
C and C++ support one's complement, if the hardware provides it.
它与零和舍入有关。如果使用第一个补码,最终可能会得到两个零。请参阅此处了解更多信息。
It has to do with zero and rounding. If you use 1st complement, you can end up have two zeros. See here for more info.
对于数字代码来说,符号-数值表示会更好。缺乏对称性是 2 的补码的一个真正问题,并且也排除了许多有用的(面向数字的)位黑客。 2 的补码还引入了一些棘手的情况,其中算术运算可能不会给出您认为可能的结果。所以你必须注意分裂、转移和否定。
Sign-magnitude representation would be much better for numeric code. The lack of symmetry is a real problem with 2's complement and also precludes a lot of useful (numeric orientated) bit-hacks. 2's complement also introduces trick situations where an arithmetic operation may not give you the result you think it might. So you must be mindful with regards to division, shifting and negation.