簡體   English   中英

C ++:奇怪的數學結果

[英]C++: Strange math results

以下計算結果為“1”。

unsigned long iEndFrame = ((4294966336 + 1920 - 1) / 1920) + 1;

有誰知道為什么? 我以為unsigned long可以解決這個問題。

非常感謝你的幫助。

計算右側的值的類型為unsigned intint

4294966336 + 1920 = 4294968256

假設sizeof(unsigned int) == 4 ,這會溢出,留下960

(960-1)/1920 = 0

(由於整數運算中的舍入)。 這讓你失望

0 + 1 = 1

如果要使用較大的類型執行計算(並假設sizeof(unsigned long) > sizeof(unsigned int) ),則需要在計算中使用強制轉換

unsigned long iEndFrame = (((unsigned long)4294966336 + 1920 - 1) / 1920) + 1;

或者,如Slava所述,使用UL后綴將其中一個文字值設置為unsigned long類型

unsigned long iEndFrame = ((4294966336UL + 1920 - 1) / 1920) + 1;

“我以為無條件的長期可以解決這個問題。” - 我不確定你的意思。 您評估的表達式中沒有任何內容表明它應該使用unsigned long 您最終使用它初始化unsigned long變量的事實對評估過程沒有影響。 初始化表達式完全獨立於此處理。

現在,在C ++語言中,未加十進制的十進制整數文字總是具有簽名類型。 不允許編譯器為表達式中使用的任何文字選擇無符號類型。 編譯器需要使用intlong intlong long int (最后一個 - 在C ++ 11中),具體取決於文字的值。 允許編譯器使用依賴於實現的擴展積分類型,但僅限於它們已簽名 如果所有簽名類型都太小,程序的行為是不確定的。

如果我們假設我們正在使用具有寬度為“傳統”16位,32位或64位的整數類型的典型現實平台,那么這里只有兩種可能性

  • 如果在您的平台上所有有符號整數類型都太小而無法表示4294966336 ,那么您的程序具有未定義的行為 故事結局。

  • 如果至少有一個有符號整數類型足夠4294966336 ,則應該沒有評估溢出,並且您的表達式應該計算為2236963

因此,對於唯一的真正的語言級別的解釋1的結果是,你正在運行到不確定的行為,因為所有的符號類型太小,無法代表你在表達式中使用的文字。

如果在您的平台上,某些有符號整數類型實際上足夠大以表示4294966336 (即某些類型至少有64位),那么結果只能通過編譯器被破壞的事實來解釋。

PS請注意,用於評估的unsigned int的可能性僅存在於舊的C語言 - C89 / 90中。 這將為您獲得的結果產生第三種解釋。 但是,同樣,這種解釋只適用於C89 / 90編譯器,而不適用於C ++編譯器或C99編譯器。 你的問題被標記為[C ++]。

我打算留下這個評論,但沒有足夠的聲譽。 無論如何,我想分享這個,因為根據我的理解,我認為有兩個組件可以解決問題,其中一個可能沒有得到正確回答。

  • 首先,您需要明確您正在使用的數據類型,即使用UL等后綴或顯式類型轉換。 我認為其他答案已經足夠清楚了。
  • 其次,您需要選擇足夠大的數據類型。

你已經說過“我認為unsigned long可以解決這個問題”,其他答案似乎證實了這一點,但是從我所知道的情況來看 - 並且現在仔細檢查以確保 - unsigned long可能不夠大。 保證至少為4294967295 ,這對於您的用例來說太小了。 具體來說,我剛剛在Windows下使用VC ++進行了檢查,並且編譯為32位和64位,定義ULONG_MAX為4294967295

您可能需要做的是使用“ULL”后綴並使用unsigned long long ,因為它的最大值似乎至少為18446744073709551615 即使有平台定義unsigned long足夠大到你的目的,我想你可能想要使用實際保證足夠大的數據類型。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM