长期未加签名

neo*_*003 12 c x86-64 integer-overflow addition extended-precision

我想获得在c中添加两个无符号64位整数的进位位。如果需要,我可以使用x86-64 asm。码:

#include <stdio.h>

typedef unsigned long long llu;

int main(void){
  llu a = -1, b = -1;
  int carry = /*carry of a+b*/;
  llu res = a+b;
  printf("a+b = %llu (because addition overflowed), carry bit = %d\n", res, carry);
  return 0;
}
Run Code Online (Sandbox Code Playgroud)

Joh*_*ger 10

作为@EugeneSh。观察到,进位为0或1。而且,由于ab都具有相同的无符号类型,即使算术结果超出其类型范围,它们的总和也定义良好。此外,总和的(C)结果将小于两者,a并且b在发生溢出时将小于两者,否则将更大,因此我们可以使用以下事实:C关系运算的值等于0或1,以将进位表示为

carry = (a + b) < a;
Run Code Online (Sandbox Code Playgroud)

那不需要任何标题,也不依赖于特定的上限,甚至不依赖于a并且b具有相同的类型。只要两者都具有无符号类型,它就可以正确报告总和是否溢出它们较宽的类型或unsigned int(以较宽者为准),这与它们的总和设置进位相同。作为奖励,它是用总和本身来表示的,我认为可以清楚地说明正在测试什么。

  • 警告:将其扩展为`carry_out =(a + b +进位_进位)&lt;a` *无效*,因为例如`b = 0xFFFF ...`和`carry_in = 1`已经产生了您赢得的进位不会检测到a + 0 &lt;a为假。但是,是的,对于带进位但不带进位的添加,效果很好。而且,现代编译器通常可以将c + d +进位优化为adc指令。您只会遇到使编译器发出add / adc / adc / adc链的大问题,在这里您需要使用来自`adc`而不是`add`的结转。 (3认同)
  • @ neo5003:您可以使用投票箭头下方的对勾标记将答案标记为已接受。 (2认同)

Eug*_*Sh. 7

进位可以是011如果有环绕,0否则。如果a + b > ULONG_LONG_MAX为true ,则发生环绕。请注意,这是数学上的问题,而不是C方面的问题,就好像a + b实际上是在溢出一样,这将不起作用。相反,您想将其重新排列为a > ULONG_LONG_MAX - b。因此,进位价值为:

carry = a > ULONG_LONG_MAX - b ? 1 : 0;
Run Code Online (Sandbox Code Playgroud)

或任何同等的首选样式。

  • 别忘了包含limits.h

  • `?1:0`是多余的。 (2认同)