我有一個乘法線可能導致輸出大於64位值。 (最大我可以保持)。確定乘法輸出是否適合64位的最大值
我想確定什麼是確定輸出是否大於64位的最佳方法。
我嘗試了一些類似的東西。
uint64_t val1, val2, val3;
if ((val1 * val2 * val3) > UINT64_MAX) {
//warning message
}
else {
//do something
}
變量被初始化爲一些值。
我有一個乘法線可能導致輸出大於64位值。 (最大我可以保持)。確定乘法輸出是否適合64位的最大值
我想確定什麼是確定輸出是否大於64位的最佳方法。
我嘗試了一些類似的東西。
uint64_t val1, val2, val3;
if ((val1 * val2 * val3) > UINT64_MAX) {
//warning message
}
else {
//do something
}
變量被初始化爲一些值。
乘法兩個無符號(!)任意大小的整數的a * b
,我們稱這類T
,就會溢出,當且僅當結果會比T
可以容納的最大數量。標準庫可以使用std::numeric_limits
訪問任何類型的最大數量T
。
上面的語句也可以被寫爲: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
。在自定義類型中標記溢出的類似實現將確保您可以輕鬆檢測鏈式計算中的溢出,例如三個數字的產品。關於自定義類型的一點是,您不必編寫要被計算兩次的表達式:作爲計算本身加上事先的溢出檢查。
你可以閱讀這個問題的答案:http://stackoverflow.com/questions/199333/best-way-to-detect-integer-overflow-in-cc – Gorgen 2013-04-05 10:06:16
另請參閱http://stackoverflow.com/問題/ 8534107/UINT64檢測-乘法的-叔整數溢出-與-C – salva 2013-04-05 11:00:56