2013-06-26 36 views
10

考慮一個典型的絕對值函數(其中爲參數的緣故整體式最大尺寸爲長):有沒有一種安全的方法來獲得有符號整數的無符號絕對值,而不會觸發溢出?

unsigned long abs(long input); 

一個天真的實現,這可能看起來像:

unsigned long abs(long input) 
{ 
    if (input >= 0) 
    { 
     // input is positive 
     // We know this is safe, because the maximum positive signed 
     // integer is always less than the maximum positive unsigned one 
     return static_cast<unsigned long>(input); 
    } 
    else 
    { 
     return static_cast<unsigned long>(-input); // ut oh... 
    } 
} 

這代碼觸發未定義的行爲,因爲input的否定可能溢出,並且觸發有符號的整數溢出是未定義的行爲。例如,在2s補碼機器上,std::numeric_limits<long>::min()的絕對值將大於std::numeric_limits<long>::max()

圖書館作者可以做些什麼來解決這個問題?

回答

16

可以先投射到未簽名的變體。這提供了明確定義的行爲。相反,代碼如下所示:

unsigned long abs(long input) 
{ 
    if (input >= 0) 
    { 
     // input is positive 
     return static_cast<unsigned long>(input); 
    } 
    else 
    { 
     return -static_cast<unsigned long>(input); // read on... 
    } 
} 

我們調用兩個明確定義的操作。轉換成無符號的一個符號整數既受N3485 4.7 [conv.integral]/2來定義:

如果目標類型是無符號,所得到的值是至少無符號整數全等到源整數(模2^n其中n是用於表示無符號類型的位數)。 [注:在二進制補碼錶示中,這種轉換是概念性的,並且位模式沒有變化(如果沒有截斷)。 - 尾註]

這基本上說,當進行從有符號到無符號的特定轉換時,可以採用無符號樣式環繞。

的無符號整數的否定既受5.3.1 [expr.unary.op]/8定義:

一個無符號的數量的負是通過從2 ^減去其值n來計算,其中n是提升操作數中的位數。

這兩個要求有效強制實施到像一個二進制補碼機操作會,即使底層機器是1的補碼或符號的振幅機。

+1

很好的答案,儘管你自己的問題,但+1。 – Bathsheba

相關問題