14#ifndef OR_TOOLS_UTIL_SATURATED_ARITHMETIC_H_
15#define OR_TOOLS_UTIL_SATURATED_ARITHMETIC_H_
21#include "absl/base/casts.h"
22#include "absl/log/check.h"
54 return x == std::numeric_limits<int64_t>::min() ||
55 x == std::numeric_limits<int64_t>::max();
62 return v ==
kint64min ? std::numeric_limits<int64_t>::max()
83 static_assert(
static_cast<uint64_t
>(-1LL) == ~0ULL,
84 "The target architecture does not use two's complement.");
85 return absl::bit_cast<int64_t>(
static_cast<uint64_t
>(x) +
86 static_cast<uint64_t
>(y));
90 static_assert(
static_cast<uint64_t
>(-1LL) == ~0ULL,
91 "The target architecture does not use two's complement.");
92 return absl::bit_cast<int64_t>(
static_cast<uint64_t
>(x) -
93 static_cast<uint64_t
>(y));
104 return ((x ^ sum) & (y ^ sum)) < 0;
132template <
typename IntegerType>
134 const int64_t x = a.value();
135 const int64_t y = b->value();
152#if defined(__GNUC__) && !defined(__clang_) && defined(__x86_64__)
153inline int64_t CapAddAsm(int64_t x, int64_t y) {
158 "\t" "addq %[y],%[result]"
159 "\n\t" "cmovoq %[cap],%[result]"
160 : [result]
"=r"(result)
161 :
"[result]" (result), [y]
"r"(y), [cap]
"r"(cap)
167inline int64_t CapSubAsm(int64_t x, int64_t y) {
172 "\t" "subq %[y],%[result]"
173 "\n\t" "cmovoq %[cap],%[result]"
174 : [result]
"=r"(result)
175 :
"[result]" (result), [y]
"r"(y), [cap]
"r"(cap)
183inline int64_t CapProdAsm(int64_t x, int64_t y) {
194 "\n\t" "imulq %[y],%[result]"
195 "\n\t" "cmovcq %[cap],%[result]"
196 : [result]
"=r"(result)
197 :
"[result]" (result), [y]
"r"(y), [cap]
"r"(cap)
207#if defined(__clang__)
208inline int64_t CapAddBuiltIn(int64_t x, int64_t y) {
211 const bool overflowed = __builtin_add_overflow(x, y, &result);
212 return overflowed ? cap : result;
215inline int64_t CapSubBuiltIn(int64_t x, int64_t y) {
218 const bool overflowed = __builtin_sub_overflow(x, y, &result);
219 return overflowed ? cap : result;
223inline int64_t CapProdBuiltIn(int64_t x, int64_t y) {
226 const bool overflowed = __builtin_mul_overflow(x, y, &result);
227 return overflowed ? cap : result;
247 return n < 0 ? ~static_cast<uint64_t>(n) + 1 :
static_cast<uint64_t
>(n);
265 const int kMaxBitIndexInInt64 = 63;
266 if (msb_sum <= kMaxBitIndexInInt64 - 2)
return x * y;
269 if (a == 0 || b == 0)
return 0;
271 if (msb_sum >= kMaxBitIndexInInt64)
return cap;
275 const uint64_t u_prod = a * b;
281 if (u_prod >=
static_cast<uint64_t
>(cap))
return cap;
282 const int64_t abs_result = absl::bit_cast<int64_t>(u_prod);
283 return cap < 0 ? -abs_result : abs_result;
292inline int64_t
CapAdd(int64_t x, int64_t y) {
293#if defined(__GNUC__) && !defined(__clang__) && defined(__x86_64__)
294 return CapAddAsm(x, y);
295#elif defined(__clang__)
296 return CapAddBuiltIn(x, y);
305#if defined(__clang__)
306 return __builtin_add_overflow(x, *y, y);
317inline int64_t
CapSub(int64_t x, int64_t y) {
318#if defined(__GNUC__) && !defined(__clang__) && defined(__x86_64__)
319 return CapSubAsm(x, y);
320#elif defined(__clang__)
321 return CapSubBuiltIn(x, y);
329 *target =
CapSub(*target, amount);
333#if defined(__GNUC__) && defined(__x86_64__)
338 return CapProdAsm(x, y);
339#elif defined(__clang__)
340 return CapProdBuiltIn(x, y);
348 static_assert(std::is_floating_point_v<T> || std::is_integral_v<T>);
349 if constexpr (std::is_integral_v<T>) {
350 if constexpr (std::is_same_v<T, int64_t>) {
354 std::is_same_v<T, int32_t>,
355 "CapOrFloatAdd() on integers only works for int and int64_t");
356 const int64_t sum = int64_t{x} + y;
uint64_t uint_abs(int64_t n)
In SWIG mode, we don't want anything besides these top-level includes.
int64_t SubOverflows(int64_t x, int64_t y)
bool AtMinOrMaxInt64(int64_t x)
Checks if x is equal to the min or the max value of an int64_t.
bool AddHadOverflow(int64_t x, int64_t y, int64_t sum)
int64_t CapAdd(int64_t x, int64_t y)
void CapAddTo(int64_t x, int64_t *y)
int64_t CapWithSignOf(int64_t x)
Returns kint64max if x >= 0 and kint64min if x < 0.
int64_t TwosComplementAddition(int64_t x, int64_t y)
-------— Overflow utility functions -------—
int64_t CapSub(int64_t x, int64_t y)
void CapSubFrom(int64_t amount, int64_t *target)
Updates *target with CapSub(*target, amount).
bool AddIntoOverflow(int64_t x, int64_t *y)
int64_t CapAddGeneric(int64_t x, int64_t y)
T CapOrFloatAdd(T x, T y)
bool AddOverflows(int64_t x, int64_t y)
int64_t CapProd(int64_t x, int64_t y)
bool SubHadOverflow(int64_t x, int64_t y, int64_t diff)
int64_t TwosComplementSubtraction(int64_t x, int64_t y)
int64_t CapAbs(int64_t v)
int64_t CapProdGeneric(int64_t x, int64_t y)
bool SafeAddInto(IntegerType a, IntegerType *b)
int64_t CapSubGeneric(int64_t x, int64_t y)
int64_t CapOpp(int64_t v)
Note(user): -kint64min != kint64max, but kint64max == ~kint64min.
int MostSignificantBitPosition64(uint64_t n)
static const int32_t kint32min
static const int64_t kint64max
static const int32_t kint32max
static const int64_t kint64min