Si vous êtes prêt à utiliser de l'assemblée ou intrinsèques, je pense avoir une solution optimale.
Pour la soustraction:
Nous pouvons utiliser l' sbb
enseignement
Dans MSVC, nous pouvons utiliser la fonction intrinsèque _subborrow_u64 (également disponible dans d'autres bits tailles).
Voici comment il est utilisé:
// *c = a - (b + borrow)
// borrow_flag is set to 1 if (a < (b + borrow))
borrow_flag = _subborrow_u64(borrow_flag, a, b, c);
Voici comment on pourrait l'appliquer à votre situation
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;
}
Pour plus:
Nous pouvons utiliser l' adcx
enseignement
Dans MSVC, nous pouvons utiliser la fonction intrinsèque _addcarry_u64 (également disponible dans d'autres bits tailles).
Voici comment il est utilisé:
// *c = a + b + carry
// carry_flag is set to 1 if there is a carry bit
carry_flag = _addcarry_u64(carry_flag, a, b, c);
Voici comment on pourrait l'appliquer à votre situation
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;
}
Je n'aime pas celui-ci autant que la soustraction, mais je pense que c'est assez chouette.
Si l'ajouter les débordements, carry_flag = 1
. Pas-ing carry_flag
rendements 0, !carry_flag * result = 0
lorsqu'il y a dépassement de capacité. Et depuis 0 - 1
sera de définir la unsigned partie intégrante de la valeur à son maximum, la fonction retourne le résultat de l'addition s'il n'y a pas de report et de retour au max, le choix de la valeur intégrale si il y a transporter.