- A+

I have a fixed-point implementation for some financial application. It's basically an integer wrapped in a class that is based on the number of decimals given `N`

treated as a decimal number. The class is paranoid and checks for overflows, but when I ran my tests in release mode, and they failed, and finally I created this minimal example that demonstrates the problem:

`#include <iostream> #include <sstream> template <typename T, typename U> typename std::enable_if<std::is_convertible<U, std::string>::value, T>::type FromString(U&& str) { std::stringstream ss; ss << str; T ret; ss >> ret; return ret; } int main() { int NewAccu=32; int N=10; using T = int64_t; T l = 10; T r = FromString<T>("1" + std::string(NewAccu - N, '0')); if (l == 0 || r == 0) { return 0; } T res = l * r; std::cout << l << std::endl; std::cout << r << std::endl; std::cout << res << std::endl; std::cout << (res / l) << std::endl; std::cout << std::endl; if ((res / l) != r) { throw std::runtime_error( "FixedPoint Multiplication Overflow while upscaling [:" + std::to_string(l) + ", " + std::to_string(r) + "]"); } return 0; } `

This happens with Clang 6, my version is:

`$ clang++ --version clang version 6.0.0-1ubuntu2 (tags/RELEASE_600/final) Target: x86_64-pc-linux-gnu Thread model: posix InstalledDir: /usr/bin `

It's funny because it's an impressive optimization, but this ruins my application and prevents me from detecting overflows. I was able to reproduce this problem in g++ here. It doesn't throw an exception there.

Notice that the exception is thrown in debug mode, but it's not in release mode.

As *@Basile* already stated, signed integer overflow is an *undefined behavior*, so the compiler can handle it in any way - even optimizing it away to gain a performance advantage. So **detecting** integer overflow after its occurence is way too late. Instead, you should **predict** integer overflow just before it occurs.

Here is my implementation of overflow prediction of integer multiplication:

`#include <limits> template <typename T> bool predict_mul_overflow(T x, T y) { static_assert(std::numeric_limits<T>::is_integer, "predict_mul_overflow expects integral types"); if constexpr (std::numeric_limits<T>::is_bounded) { return ((x != T{0}) && ((std::numeric_limits<T>::max() / x) < y)); } else { return false; } } `

The function returns `true`

if the integer multiplication `x * y`

is predicted to overflow.

Note that while `unsigned`

overflow is well-defined in terms of modular arithmetic, `signed`

overflow is an *undefined behavior*. Nevertheless, the presented function works for `signed`

and `unsigned`

`T`

types as well.