A multiplication a * b
of two unsigned (!) integer numbers of arbitrary size, let's call this type T
, will overflow if and only if the result would be greater than the maximum number T
can hold. The standard library can access the maximum number of any type T
using std::numeric_limits
.
The above statement can also be written as: a * b
will overflow if and only if a > max(T) / b
, which is the same as b > max(T) / a
(where /
is an integer division and max(T)
is the maximum number T
can hold).
Example: Let's say T = uint8_t
, so max(T) == 255
. A couple of examples for demonstration:
a | 16 | 15 | 14
b | 16 | 17 | 18
---------------------------------
a * b | 256 | 255 | 252
overflow? | yes | no | no
---------------------------------
max(T)/b | 15 | 15 | 14
a > max(T)/b? | yes | no | no
Use this method to check if a multiplication a * b
will overflow:
#include <limits.h>
template<typename T>
bool multiplicationWillOverflow(T a, T b) {
return a > std::numeric_limits<T>::max() / b;
}
Then, use this method twice on your product of three numbers:
uint64_t val1, val2, val3;
if (multiplicationWillOverflow(val1, val2)) {
//warning message
}
uint64_t product12 = val1 * val2,
else if (multiplicationWillOverflow(product12, val3)) {
//warning message
}
uint64_t product123 = product12 * val3;
Another option is to encapsulate the multiplication and the check in one method. Throw an exception if an overflow occurs.
template<typename T>
T safeMultiplication(T a, T b) {
if (a > std::numeric_limits<T>::max() / b)
throw ...;
else
return a * b;
}
You can encapsulate this behavior in a custom type, which overloads arithmetic operators and throws if an overflow would happen.
Don't use exceptions if you expect overflows as "normal behavior" / under "normal circumstances". In such cases, use an error parameter / a flag in a custom type instead.
A similar thing is done in floating point arithmetic with NaN
exceptional states: Continuing a calculation with a NaN
value will result in NaN
again. A similar implementation for flagging overflow in your custom type will make sure you can detect overflow in chained calculations, like your product of three numbers, easily. The point about a custom type is that you don't have to write the expression to be calculated twice: As the calculation itself plus the overflow checking in advance.