C++实现uint64带进位加法的逻辑矛盾及位运算作用咨询
问题1:逻辑运算结果和预期不符的原因
你观察到的矛盾完全是两个上下文的变量混淆+类型隐式转换导致的,本质上你以为的0||1根本不是函数实际执行的逻辑:
- 你在
main函数中打印的两个条件值,用的是main作用域下未修改的原始变量:operand1还是初始值10000,carry是定义为char类型的255。绝大多数编译器默认char是有符号类型,赋值255实际存储的是补码形式的-1。比较~operand1 < carry时,有符号的-1会先提升为int,再和uint64_t类型的~operand1比较时,int会被转换为uint64_t类型的全1(即UINT64_MAX),因此~10000 < UINT64_MAX的结果为1,这是你看到的(~operand1 < carry): 1的来源。 - 但在
add_uint64_generic函数内部,逻辑完全不同:- 函数第一步就执行了
operand1 += operand2,此时operand1的值已经变为12000,不再是原来的10000; - 函数形参
carry是unsigned char类型,传入的-1会被转换为无符号的255; - 执行return语句的判断时:
operand1 < operand2即12000 < 2000结果为0;~operand1 < carry即~12000 < 255,~12000是UINT64_MAX - 12000,是一个远大于255的无符号数,结果也为0。
所以函数实际执行的是0 || 0,返回0,和你在main里测试的0||1没有任何关系。
- 函数第一步就执行了
问题2:~operand1和进位逻辑的关联
这段代码实现的是带输入进位的64位无符号加法,总计算逻辑为结果 = operand1 + operand2 + 输入进位carry,分两步判断是否产生溢出进位:
- 第一步
operand1 += operand2:无符号加法溢出的判断规则就是结果小于任意一个操作数,因此operand1 < operand2为真就说明第一步加法溢出,产生了进位。 - 第二步加输入进位:无符号加法
a + b溢出的充要条件是a > UINT64_MAX - b。对于无符号数来说,按位取反~a等价于UINT64_MAX - a,因此~operand1 < carry可以转换为carry > UINT64_MAX - operand1,也就是operand1 + carry > UINT64_MAX,说明第二步加进位的时候也产生了溢出进位。
两个条件只要有一个为真,说明整个加法过程产生了进位,因此用或运算拼接作为最终的进位返回值。
你测试用例的总结果为10000+2000+255=12255,确实没有溢出,返回进位0符合实际计算结果。
内容的提问来源于stack exchange,提问作者Rafaelo
相关产品推荐
相关产品推荐

