【问题标题】:Is one's complement a real-world issue, or just a historical one?一个人的补充是一个现实世界的问题,还是只是一个历史问题?
【发布时间】:2010-09-14 18:39:33
【问题描述】:

Another question 询问如何确定 C 中的奇数/偶数,并且 C 标准允许的 one's complement-based 系统的惯用 (x & 1) 方法被正确标记为损坏。

系统真的存在于计算机博物馆之外的“现实世界”中吗?自 1970 年代以来我一直在编码,我很确定我从未遇到过这样的野兽。

真的有人为这样的系统开发或测试代码吗?如果没有,我们应该担心这些事情还是应该将它们与纸带和穿孔卡片一起放入Room 101...?

【问题讨论】:

  • 我知道这个问题已经过时了,但是任何阅读它的人都应该知道(x & 1U) is 有效(注意U)用于确定偶数/奇数-补码或符号/幅度实现。
  • @R.你确定吗?:在 32 位 1 的 comp 中,-1 表示为 0xFFFFFFFE,所以 (0xFFFFFFFE & 0x00000001) = 0x00000000 = false。
  • @Roddy:在所有系统上计算 (MAX_INT+1- (-value)) 都需要转换负符号整数。对于使用二进制补码数学的系统,计算结果将具有与原始有符号整数相同的位表示,因此许多编译器将简单地重新解释该值而不生成任何代码来对其进行操作。然而,在具有反码或有符号幅度计算的系统上,编译器必须为类型转换生成代码以确保定义的行为。
  • @Supercat - 很有趣,谢谢! re: (MAX_INT+1- (-value)) - 你有这个来源吗?是否仅在 C99 标准中?
  • 维基百科signed number representations上的文章提到“Unisys ClearPath Dorado系列主机使用反码”。

标签: c history numerical


【解决方案1】:

我决定找一个。 Unisys ClearPath 系统有一个 ANSI C 编译器(是的,他们称其为“美国国家标准 C”,甚至其 PDF 文档最后一次更新是在 2013 年。该文档可在 online 获得;

有符号类型都使用反码表示,具有以下属性:

Type                 | Bits | Range
---------------------+------+-----------------
signed char          |   9  |  -2⁸+1 ...  2⁸-1
signed short         |  18  | -2¹⁷+1 ... 2¹⁷-1
signed int           |  36  | -2³⁵+1 ... 2³⁵-1
signed long int      |  36  | -2³⁵+1 ... 2³⁵-1
signed long long int |  72  | -2⁷¹+1 ... 2⁷¹-1

值得注意的是,它还默认支持不合格的unsigned intunsigned long,范围从0 ... 2³⁶ - 2,但可以通过pragma更改为0 ... 2³⁶ - 1

【讨论】:

  • 仅供参考,“ANSI C”是指第一个 C 标准 (C89/C90) 的常用方式。换句话说,ANSI C == C89。
  • 出于好奇,它如何代表signed long long int?它是使用“直接”的二进制表示,还是做了一些有趣的事情?如果系统可以支持具有直接二进制表示的 71 位有符号值,那么支持符合标准的 70 位无符号类型应该没有问题,但事实并非如此。这让我想知道它是否可能使用直接二进制表示以外的其他东西(这对于有符号类型是允许的,但对于无符号类型是允许的)。
【解决方案2】:

这一切都归结为了解你的根源。
是的,这在技术上是一项古老的技术,我可能会按照其他人在该问题中的建议进行操作,并使用模 (%) 运算符来确定奇数或偶数。 但是了解什么是 1s 补码(或 2s 补码)总是一件好事。无论您是否使用过它们,您的 CPU 一直在处理这些事情。所以理解这个概念永远不会有坏处。现在,现代系统做到了,因此您通常不必担心类似的事情,因此它在某种程度上已成为 Programming 101 课程的主题。但是你必须记住,有些人实际上仍然会在“现实世界”中使用它......例如,与普遍的看法相反,有些人仍然使用汇编!不多,但直到 CPU可以理解原始 C# 和 Java,有人 仍然必须理解这些东西。

哎呀,你永远不知道什么时候你会发现自己在做一些你真正需要执行二进制数学的事情,而 1s 补码会派上用场。

【讨论】:

  • 谢谢。完全同意你需要学习它,但你不应该担心它——比如 6 位字节,以及核心内存是如何工作的。顺便说一句,这是“补充”,而不是“赞美”。一个人的赞美可能是“这是你今天穿的很好的标志”。
  • 我使用 Steve Yegge 的五个领域 (steve.yegge.googlepages.com/…) 对软件工程师进行了很多采访,您最好相信其中一个领域是位和字节。如果你想成为一个好的 SDE,你必须了解二进制数字系统,而二进制补码是其中的一部分。我希望任何体面的计算机科学课程都能在计算机组织课程中涵盖这一点。
  • @Roddy:C 或 C++ 中实际上不允许使用 6 位字节:一个字节中的最小位数(C / C++ 定义为sizeof(char))为 8。
  • @DavidStone 实际上sizeof(char) 被定义为1。你想引用的是CHAR_BIT
  • @Ruslan:抱歉,我写的内容含糊不清。我想说的是 C 和 C++ 将一个字节定义为sizeof(char),其中的最小位数是 8。
【解决方案3】:

有趣的是,人们在 comp.std.c在 1993 年问了同样的问题,没有人能指出当时使用的补码机器。 p>

所以是的,我认为我们可以自信地说,一个人的补语属于我们历史的一个黑暗角落,实际上已经死了,不再是一个问题。

【讨论】:

  • 链接的文章提出了一个没有人回答的问题(“还有标准想要支持的补充机器吗?哪些机器?......”)但是鉴于该线程是关于不同主题的,我不会认为这是一个详尽的调查。
  • @JosiahYoder:你不能提供没有使用某些东西的证据。没有人可以指出特定的相关架构,而不是在 comp.std.c 上的那个线程上,也不是在这个关于 SO 的问题中,这是您可以获得的最佳证据。如果您不知道,comp.std.c 是一个用于讨论 C 标准演变的邮件列表,包括标准委员会的成员,并且在当时是一个更重要的沟通渠道。
【解决方案4】:

一个人的补充是一个现实世界的问题,还是只是一个历史问题?

是的,它仍然在使用。它甚至用于现代英特尔处理器。来自Intel® 64 and IA-32 Architectures Software Developer’s Manual2A,第 3-8 页:

3.1.1.8 描述部分

然后每条指令由信息部分的数量来描述。 “描述”部分更详细地描述了指令的用途和所需的操作数。

描述部分可能使用的术语摘要:
* 旧版 SSE:指 SSE、SSE2、SSE3、SSSE3、SSE4、AESNI、PCLMULQDQ 以及任何未来的指令集,这些指令集引用 XMM 寄存器并在没有 VEX 前缀的情况下进行编码。
* VEX.vvvv。指定源或目标寄存器的 VEX 位域(以 1 的补码形式)。
* rm_field:ModR/M r/m 字段和任何 REX.B 的简写
* reg_field:ModR/M reg 字段和任何 REX.R 的简写

【讨论】:

  • 编译后的代码是否真的包含一个用 1 的补码编码的 VEX 位域?
  • @JosiahYoder 当然,每当使用 VEX 编码指令时,它都会反转一些字段。与 EVEX 前缀类似。我相信这样做是为了避免与 32 位模式指令发生冲突,这些指令已从本机 64 位模式中删除,但必须与所有 SIMD 扩展一起在 32 位模式下工作。
  • @JosiahYoder 如果目标 CPU 支持 AVX,那么例如GCC 将发出 VEX 编码的指令,即使它们可以在没有 VEX 前缀的情况下进行编码(例如大多数 SSE、SSE2、... 指令)。随着编译器的自动向量化能力越来越强,这些指令在编译器的输出中变得越来越普遍。至于“我相信这已经完成......”,我指的是倒置,而不是与 2s 补码相比。无论如何,这实际上并不是你在编写普通的高级应用程序时会遇到的——它只是特定类指令的编码方式的一个特点。
  • @jww - 很抱歉投了反对票。我不经常使用它们。但是,尽管 1 的补码是位的反转,但它也是一个数字系统,用于表示正数和负数,同时具有 +0 和 -0 以及与 2 的补码相比的各种其他怪癖。尽管文档在此处使用术语 1 的补码,但它们并不表示广义上的 1 的补码。
  • 首先,请阅读 OP,它清楚地询问了 C 语言上下文中的系统(即架构),而不是应用程序。其次,CRC 根本不将位模式解释为负数,而是按位非的另一种算法使用,而不是 OP 询问的负数表示形式的补码。
【解决方案5】:

RFC 791 p.14 将 IP 标头校验和定义为:

校验和字段是报头中所有 16 位字的反码和的 16 位反码。为了计算校验和,校验和字段的值为零。

因此,在现实世界中,发送的每个 IP 数据包中仍然大量使用补码。 :)

【讨论】:

  • 嗯,嗯...我指的是补码作为表示负整数的一种方式,而不是按位反转的一种方式,但您可能知道这一点。 +1 努力:-)
  • 关于二进制补码校验和的一个有趣事实是,如果使用 16 位字读取源数据中的字节对并同样存储两字节校验和,则相同的代码将适用于大端和小端架构。
【解决方案6】:

我在 80 年代使用的 CDC Cyber​​ 18 是一台 1s 补码机,但那是将近 30 年前的事了,从那以后我就再也没有见过一台(不过,那也是我最后一次在非个人电脑)

【讨论】:

    【解决方案7】:

    我在遥测领域工作,我们的一些客户有旧的模数转换器,仍然使用 1 的补码。前几天我只需要编写代码将 1 的补码转换为 2 的补码以进行补偿。

    所以是的,它仍然存在(但你不会经常遇到它)。

    【讨论】:

    • I/O 存在有符号幅度、偏移二进制和一个补码,但实际上几乎总是在读取它们后立即通过代码转换为偏移二进制或二进制补码在。
    • 能否请有相关经验的人提供一些可能有助于回答 OP 问题的品牌名称、URL 或搜索关键字?这个答案有助于将我的搜索关键字从“现代人的补充平台”更改为“现代人的补充 a2d 转换器”,但我相信它可以更明确。
    • 我是否正确,这个答案不是在谈论 int 在内存中本机使用二进制补码表示的 C/C++ 平台,而只是在谈论 wire 格式 i> (用于与某些外围设备通信)它指定某些/所有字段中的负数必须编码为一个补码?如果是这样,这在本质上类似于上面的 RFC 791 示例。
    • @Quuxplusone 我认为这与 RFC 971 示例不同。来自 ADC 的 1 的补码代表数字化双极(正负)信号。然后,这个 ADC 可以用作直接输入到 1 的补码机器中,然后可以用 C/C++ 进行处理;但我不知道有任何这样的例子。有人提到,ADI 等主要供应商曾经制造过这类 ADC,但即使是他们的参考资料也表明这种情况很少见(参见analog.com/media/en/training-seminars/design-handbooks/…
    • …这样的 ADC 也可能已经足够老了,以至于它不会使用任何类型的数据包或串行通信接口;相反,数字化样本的位将出现在 IC 的引脚上(“并行”)。
    【解决方案8】:

    去年某个时候,我们离开了 1960 年代的 Honeyboxen,这使它成为我们现场最古老的机器。这是二进制补码。这并不是说知道或意识到一个人的补语是一件坏事。只是,你今天可能永远不会遇到互补问题,不管你在工作中做了多少计算机考古。

    你更可能在整数方面遇到的问题是endian 问题(我在看着你PDP)。此外,与整数格式相比,floating point formats 会遇到更多“现实世界”(即今天)问题。

    【讨论】:

    • 几周前我在一个网站上,那里还有几个蜜箱在运行!看到机器通电,我感到非常震惊。
    【解决方案9】:

    我从来没有遇到过一个人的补码系统,而且我一直在编码,只要你有。

    但我确实遇到了 9 的补码系统——HP-41c 计算器的机器语言。我承认这可以被认为是过时的,而且我认为他们从来没有针对这些的 C 编译器。

    【讨论】:

      猜你喜欢
      • 2014-04-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-30
      • 1970-01-01
      相关资源
      最近更新 更多