如果您愿意使用汇编或内嵌函数,我认为我有一个最优解决方案。
对于减法:
我们可以使用sbb指令。
在MSVC中,我们可以使用内嵌函数_subborrow_u64(也适用于其他位数)。
以下是它的使用方法:
// *c = a - (b + borrow)
// borrow_flag is set to 1 if (a < (b + borrow))
borrow_flag = _subborrow_u64(borrow_flag, a, b, c);
这是我们如何将其应用到您的情况中的方式。
uint64_t sub_no_underflow(uint64_t a, uint64_t b){
uint64_t result;
borrow_flag = _subborrow_u64(0, a, b, &result);
return result * !borrow_flag;
}
对于加法:
我们可以使用
adcx
指令
在 MSVC 中,我们可以使用内置函数
_addcarry_u64(其他位数也可用)。
以下是它的使用方法:
carry_flag = _addcarry_u64(carry_flag, a, b, c);
这是我们如何将其应用于您的情况。
uint64_t add_no_overflow(uint64_t a, uint64_t b){
uint64_t result;
carry_flag = _addcarry_u64(0, a, b, &result);
return !carry_flag * result - carry_flag;
}
我不太喜欢这个,比起减法那个,但我认为这很聪明。
如果加法溢出,
carry_flag = 1
。对
carry_flag
取反得到0,因此当发生溢出时,
!carry_flag * result = 0
。由于
0 - 1
会将无符号整数值设置为其最大值,所以如果没有进位,函数将返回加法结果,如果有进位,则返回所选整数值的最大值。
y ^ ((x ^ y) & -(x < y))
对于int
类型的变量,可以在不使用分支语句的情况下计算min(x, y)
。根据你目前所拥有的内容,这可能会成为最终解决方案的一部分。 - Bathsheba