2016-08-04 50 views
14

我正在用C++中的整數除法面臨一些奇怪的結果。我試圖計算:-2147483648/-1C++整數除法如何工作限制和負值?

我得到的是在3個不同的場景3個不同的結果:

int foo(int numerator, int denominator) { 
    int res = numerator/denominator; // produces SIGFPE, Arithmetic exception interrupt 

    cout << res << endl; 
} 

int main() { 
    int res = -2147483648/-1; 
    cout << res << endl;    // prints -2147483648 
    cout << -2147483648/-1 << endl; // prints 2147483648 
    foo(-2147483648, -1); 
    return 0; 
} 

爲什麼整數除法運算在不同情況下會產生不同的結果?

+1

值得一提的是,在VS-2015上,代碼無法編譯,稱「負整數常量轉換爲無符號類型\t」,而「一元減運算符應用於無符號類型,結果仍爲無符號」在所有'-2147483648/-1'行 –

+1

簡單的答案[這裏](http://stackoverflow.com/a/29355979/1460794)。 – wally

+2

這是visual studio如何做到這一點:'#define INT_MIN(-2147483647 - 1)//最小(有符號)整型值' – wally

回答

12

字面-2147483648/-1是由你的編譯器中是足夠寬以容納該值的數據類型計算2147483648

當文字直接打印出來時,它會正確打印值。

當文字存儲在res中時,它被轉換爲int。一個int在您的系統上似乎是32位寬。值2147483648不能表示爲一個32位有符號整數,所以演員陣營會導致溢出。在你的系統上,這個溢出結果的值爲-2147483648(可能是使用二進制補碼)。

最後,試圖在運行時執行除法(在foo功能)的情況下,SIGFPE異常發生由於溢出(因爲int數據類型不能代表結果)。

注意,所有這三個選項的依靠平臺的依賴行爲:

  • 的事實,編譯器不產生任何錯誤(或其他問題)字面計算溢出時,只是使用的數據類型大到足以容納結果
  • 是存儲字面當int溢出產生的事實,特定值(並沒有其他問題)
  • 的事實SIGFPE異常被拋出在運行時
  • 溢出時
+0

AFAICT編譯期間的整數溢出是Undefined Behavior;使用更大的數據類型是一種可能的行爲,但FirstSTep顯示,另一種行爲是錯誤的。 – MSalters

+0

@ MSalters:是的,我在最後一段中陳述的很多。 –

+0

哪一個也是錯誤的:每個平臺都必須支持足夠寬的數據類型; 'long long int'肯定夠寬。 – MSalters

12

您的結果可能是INT_MAX+1,換句話說可能會溢出。這是未定義的行爲,任何事情都可能發生。例如,編譯器可能會直接拒絕代碼。

(A系統可能INT_MAX >= 2147483648,但你會期望你的3個測試用例相同的結果)

10
int res = -2147483648/-1; 
cout << res << endl;    // prints -2147483648 
cout << -2147483648/-1 << endl; // prints 2147483648 
int res = numerator/denominator; // produces SIGFPE, Arithmetic exception interrupt 

請注意,沒有負面的integer literals

沒有負整數文字。諸如-1之類的表達式將一元減運算符應用於文字表示的值,這可能涉及隱式類型轉換。

字面2147483648大於int最大值大,所以它的類型將是long(或long long,取決於實現)。然後-2147483648的類型是long,並且計算結果(-2147483648/-1)也是long

對於第一情況下,結果2147483648long型的是implicitly convertedint,但它比的int最大值越大,結果是實現定義。 (看來結果根據代表(2的補數)這裏的規則纏,讓你得到的結果-2147483648

對於第二種情況,與long類型的結果直接打印出來,所以你得到正確的結果。

對於第3的情況下,你在做兩個int S上的計算,結果可能不適合在結果類型(即int),signed integer arithmetic operation overflow發生的行爲是不確定的。 (在此產生SIGFPE,算術異常中斷)

+0

'-2147483648'可能是'long long',例如在MSVC(它有'LONG_MAX = 2147483647') – MSalters

+0

iirc在舊版本的C++中它可能也是一個32位無符號長(它實際上並沒有改變最終結果,但它確實改變了你如何到達那裏)。 – plugwash

+0

@plugwash我對「舊」C++不太瞭解。 :)現在,它將是'long'或'long long'(自C++ 11以來),除非使用後綴'u',否則它不會是'unsigned'。該表示是實現定義的,所以'long'可以用32位整數表示。 – songyuanyao