【问题标题】:What method does the computer use to add unsigned integers计算机用什么方法把无符号整数相加
【发布时间】:2018-02-03 13:15:35
【问题描述】:
int main(){
unsigned int num1 = 0x65764321; 
unsigned int num2 = 0x23657432;
unsigned int sum = num1 + num2;
cout << hex << sum;
return 0;
}

如果我有两个无符号整数,说 num1 和 num2。然后我告诉计算机未签名

int sum = num1 + num2; 

计算机用什么方法来相加,会不会是补码。 sum 变量会以二进制补码形式打印吗?

【问题讨论】:

  • 二进制补码在无符号数的上下文中没有意义。
  • @SamVarshavchik unsigned 溢出定义明确。
  • 我假设您的讲师正在谈论 x86 的 cpu 标志,并且该标志已设置,因为 x86 只有一个添加项,它同时执行有符号和无符号。使用适当的标志取决于您(或编译器)。 PS:虽然对结果没有影响。
  • @nwp,在一些 cmets 之后问题的文本发生了变化..@SamVarshavchik 当时是对的..
  • @ped7g:实际的 CPU 执行的操作与简单的波纹进位加法器产生相同的结果,但延迟更低。一个常见的事情是carry-lookahead,它以较小的块工作,然后修复进位。说实际的硅只是从最低位开始是不正确的。

标签: c++ assembly cpu-architecture


【解决方案1】:

2's complement 加法就实际位而言与无符号加法相同。在实际的硬件中,设计会像https://en.wikipedia.org/wiki/Carry-lookahead_adder 这样复杂,因此它可以是低延迟(不必等待进位在 32 位或 64 位上波动,因为对于add 来说,门延迟太多了是单周期延迟。)

补码和符号/大小是 C++ 允许实现使用的其他有符号整数表示,它们的环绕行为与无符号不同

例如,补码加法必须将进位返回到低位。请参阅this article about optimizing TCP checksum calculation,了解如何在仅提供 2 的补码/无符号加法的硬件上实现补码加法。 (特别是 x86)。

C++ 将带符号溢出作为未定义的行为,但真正的补码和符号/幅度硬件确实具有特定的记录行为。 reinterpret_castunsigned 位模式转换为有符号整数会给出取决于您正在运行的硬件类型的结果。 (不过,所有现代硬件都是 2 的补码。)


由于无符号补码或 2 的补码的按位运算相同,因此这完全取决于您如何解释结果。在 x86 等基于指令结果设置标志的 CPU 架构上,溢出标志仅与有符号解释相关,进位标志仅与无符号解释相关。硬件从一条指令生成两者,而不是使用单独的有符号/无符号添加指令来执行相同的操作。

请参阅 http://teaching.idallen.com/dat2343/10f/notes/040_overflow.txt,了解有关无符号进位与有符号溢出以及 x86 标志的精彩文章。


在其他架构上,例如 MIPS,没有 FLAGS 寄存器。您必须使用比较或测试指令来确定发生了什么(进位或零或其他)。 add 指令不设置标志。见this MIPS Q&A about add-with-carry for a 64-bit add on 32-bit MIPS

但是为了检测有符号溢出,add raises an exception on overflow(x86 将设置 OF),所以如果你希望它在有符号溢出时出错,你可以使用 addu 进行有符号或无符号加法。


现在这里的溢出标志是1(这是我们教练给的例子)意味着有溢出但没有进位,所以这里怎么会有溢出

您有一个 C++ 程序,而不是 x86 汇编语言程序! C++ 没有进位或溢出标志。

如果您使用非优化编译器为 x86 编译此程序,并且它使用带有两个输入的 ADD 指令,您将从该 ADD 指令中获得 OF=1CF=0

但编译器可能会使用lea edi, [rax+rdx] 进行求和而不覆盖任一输入,以及LEA doesn't set flags

或者如果编译器在编译时进行了添加,你的代码会像这样编译源代码:

cout << hex << 0x88dbb753U;

并且不会在运行时添加您的数字。 (如果您的编译器选择发出设置堆栈帧的代码,那么 iostream 库函数中当然会有很多添加,甚至可能在 main() 中添加一条 add 指令作为制作堆栈帧的一部分。)

【讨论】:

    【解决方案2】:

    我有两个无符号整数

    电脑是用什么方法添加的

    目标 CPU 架构上可用的任何方法。大多数都有一个名为 ADD 的指令。

    sum 变量会以二进制补码形式打印吗?

    二进制补码是一种用二进制表示整数类型的方法。这不是打印数字的方法。

    【讨论】:

    • 这不是未定义的行为。 num1 + num2 的结果是不可预测的。但程序表现正常。
    • @user1810087 标准另有说明。 (除非是窄字符型)
    • 2 的补码用于表示数。它使用最左边的位来表示符号。因此,该位不能再用于表示正数。正数没有“2 的补码”。
    • @user2079303 如果是这样,你能告诉我在哪里吗?因为我不认为计算无符号数字是未定义的行为。
    • @user1810087 [dcl.init] §12(数字可能因标准版本而异)“如果评估产生不确定的值,则行为未定义,但以下情况除外:” i> 所有的例外都涉及窄字符类型。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-09-07
    • 2016-02-03
    • 2013-04-30
    • 2011-08-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多