diff --git a/fixedpoint/fixedpoint.h b/fixedpoint/fixedpoint.h index 56e95c0..511cc0e 100644 --- a/fixedpoint/fixedpoint.h +++ b/fixedpoint/fixedpoint.h @@ -23,6 +23,7 @@ #include #include #include +#include #include "../internal/detect_platform.h" @@ -107,10 +108,17 @@ tIntegerType Sub(tIntegerType a, tIntegerType b) { return a - b; } -// Integer unary negative. Not saturating. Overflow is undefined behavior. +// Integer unary negative. Not saturating. In case of overflow (negating the +// most negative representable value), no Undefined Behavior: the result wraps +// around (implementation-defined, in practice back to that same most negative +// value). This mirrors the SIMD implementations of Neg (which negate in +// hardware without UB) and the UB-avoidance policy documented on ShiftLeft +// below. The negation is done through the unsigned counterpart type, where it +// cannot overflow, then converted back. template tIntegerType Neg(tIntegerType a) { - return -a; + typedef typename std::make_unsigned::type UnsignedType; + return static_cast(-static_cast(a)); } // Integer arithmetic left-shift, equivalent to multiplying with a power of two.