我有一条乘法线可以导致输出大于 64 位值。(最多我可以持有)。
我想确定确定输出是否大于 64 位的最佳方法是什么。
我尝试过一些类似的东西。
uint64_t val1, val2, val3;
if ((val1 * val2 * val3 ) > UINT64_MAX) {
//warning message
}
else {
//do something
}
变量被初始化为一些值。
a * b
两个任意大小的无符号 (!) 整数相乘,我们称之为这种类型,T
当且仅当结果大于T
可以容纳的最大数字时才会溢出。标准库可以T
使用std::numeric_limits
.
上面的语句也可以写成:a * b
当且仅当 时才会溢出a > max(T) / b
,这与b > max(T) / a
(其中/
是整数除法,max(T)
是可以容纳的最大数T
)相同。
示例:假设T = uint8_t
,所以max(T) == 255
。几个演示示例:
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
使用此方法检查乘法a * b
是否会溢出:
#include <limits.h>
template<typename T>
bool multiplicationWillOverflow(T a, T b) {
return a > std::numeric_limits<T>::max() / b;
}
然后,在您的三个数字的乘积上使用此方法两次:
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;
另一种选择是将乘法和检查封装在一个方法中。如果发生溢出则抛出异常。
template<typename T>
T safeMultiplication(T a, T b) {
if (a > std::numeric_limits<T>::max() / b)
throw ...;
else
return a * b;
}
您可以将此行为封装在自定义类型中,该类型会重载算术运算符并在发生溢出时抛出。
如果您期望溢出作为“正常行为”/在“正常情况下”,请不要使用异常。在这种情况下,请改用自定义类型中的错误参数/标志。
在具有异常状态的浮点运算中也有类似的事情NaN
:继续计算一个NaN
值将NaN
再次导致结果。在自定义类型中标记溢出的类似实现将确保您可以轻松检测链式计算中的溢出,例如您的三个数字的乘积。关于自定义类型的要点是,您不必编写要计算两次的表达式:作为计算本身加上预先的溢出检查。