C/C++ 整數乘法溢位

今天要介紹寫程式時應該要避免的 integer multiplication overflow 整數乘法溢位問題,

故事是某天我在做時間單位轉換時發生了一個小意外,
想要將 us 轉成 ms 時間單位,程式碼如下,

1
2
3
4
5
6
7
8
uint64_t us = 12345678;
uint32_t ms;

ms = us / 1000;
uint64_t us2 = ms * 1000;
cout << us << \n;
cout << ms << \n;
cout << us2 << \n;

乍看之下,好像沒什麼問題,但總是有問題不會發生在當下,而是在某個時機發生了XD,

怎麼說呢,讓我們換個例子試試

1
2
3
4
5
6
7
8
uint64_t us = 43xxxxxxx;
uint32_t ms;

ms = us / 1000;
uint64_t us2 = ms * 1000;
cout << us << \n;
cout << ms << \n;
cout << us2 << \n;

不難發現,程式執行結果不符合我們的預期,

其實問題會發生在這一行,

1
uint64_t us2 = ms * 1000;

ms 這個變數是uint32_t 大小的,其實是用uint32_t這個大小去乘1000,乘完放在uint32_t,最後再複製到uint64_t,如果ms變數裡面放的數字乘出來的結果會超過uint32_t的話,悲劇就會發生了,發生了「乘法溢位」。

所以我們應該怎麼改?
答案是,先把ms從uint32_t擴大轉換widening conversions(promotion)成uint64_t大小,這樣在計算時就會以uint64_t去作計算,

1
uint64_t us2 = uint64_t(ms) * 1000;

所以要把握一個原則,「乘法時要小心溢位」

參考
小心 int 乘法溢出! - IT閱讀
https://www.itread01.com/articles/1506858849.html
Check for integer overflow on multiplication - GeeksforGeeks
https://www.geeksforgeeks.org/check-integer-overflow-multiplication/
c - Catch and compute overflow during multiplication of two large integers - Stack Overflow
https://stackoverflow.com/questions/1815367/catch-and-compute-overflow-during-multiplication-of-two-large-integers
類型轉換與類型安全 | Microsoft Docs
https://docs.microsoft.com/zh-tw/cpp/cpp/type-conversions-and-type-safety-modern-cpp?view=msvc-160
Type conversions - C++ Tutorials
http://www.cplusplus.com/doc/tutorial/typecasting/
Type Conversion in C++ - GeeksforGeeks
https://www.geeksforgeeks.org/type-conversion-in-c/

其它相關文章推薦
C/C++ 新手入門教學懶人包
C++ virtual 的兩種用法
C/C++ 字串反轉 reverse
C/C++ call by value傳值, call by pointer傳址, call by reference傳參考 的差別
C++ 類別樣板 class template
std::sort 用法與範例
std::find 用法與範例
std::queue 用法與範例
std::map 用法與範例