Nếu bạn sẵn sàng sử dụng lắp ráp hoặc bản chất, tôi nghĩ tôi có một giải pháp tối ưu.
Đối với phép trừ:
Chúng ta có thể sử dụng sbb
hướng dẫn
Trong MSVC, chúng ta có thể sử dụng hàm nội tại _subborrow_u64 (cũng có sẵn ở các kích thước bit khác).
Đây là cách nó được sử dụng:
// *c = a - (b + borrow)
// borrow_flag is set to 1 if (a < (b + borrow))
borrow_flag = _subborrow_u64(borrow_flag, a, b, c)
Đây là cách chúng tôi có thể áp dụng nó vào tình huống của bạn
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;
}
Ngoài ra:
Chúng ta có thể sử dụngadcx
hướng dẫn
Trong MSVC, chúng ta có thể sử dụng hàm nội tại _addcarry_u64 (cũng có sẵn ở các kích thước bit khác).
Đây là cách nó được sử dụng:
carry_flag = _addcarry_u64(carry_flag, a, b, c);
Đây là cách chúng tôi có thể áp dụng nó vào tình huống của bạn
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;
}
Tôi không thích cái này nhiều như cái trừ, nhưng tôi nghĩ nó khá tiện lợi.
Nếu phần bổ sung bị tràn carry_flag = 1
,. Not-ing carry_flag
cho kết quả là 0, vì vậy !carry_flag * result = 0
khi có tràn. Và vì 0 - 1
sẽ đặt giá trị tích phân không dấu thành giá trị lớn nhất của nó, hàm sẽ trả về kết quả của phép cộng nếu không có dấu và trả về giá trị lớn nhất của giá trị tích phân đã chọn nếu có dấu.
y ^ ((x ^ y) & -(x < y))
choint
các loại đánh giámin(x, y)
mà không phân nhánh. Điều này có thể là một phần của giải pháp cuối cùng, dựa trên những gì bạn có cho đến nay.