[英]Why does the snippet throw a Floating point exception?
這個
double what;
for (int i = 1; i < (long)pow(10, 7); i++)
what = (i + i) / (i * i) - i;
引發浮點異常(核心轉儲)。 為什么? 我正在使用 clang++。
根據您的平台, int
可能是 32 位或 64 位寬。
來自[basic.fundamental]/2和[basic.fundamental]/3 [摘錄,強調我的]:
[basic.fundamental]/2
有五種標准的有符號 integer 類型:“
signed char
”、“short int
”、“int
”、“long int
”和“long long int
”。 在此列表中,每種類型提供的存儲空間至少與列表中它前面的那些一樣多。 [...] plainint
具有執行環境架構建議的自然大小; 提供其他簽名integer型號以滿足特殊需要。[basic.fundamental]/3
對於每個標准的有符號 integer 類型,存在一個對應的(但不同的)標准無符號 integer 類型:“
unsigned char
”、“unsigned short int
”、“unsigned int
”、“unsigned long int
”和“unsigned long long int
” ”,其中每一個都占用相同的存儲量,並且與對應的簽名integer類型具有相同的alignment要求; [...]有符號和無符號 integer 類型應滿足 C 標准第 5.2.4.2.1 節中給出的約束。
我們可以 go 到C11 標准草案[摘錄,強調我的]:
5.2.4.2.1 integer 類型的大小
<limits.h>
[...] 它們的實現定義值的大小(絕對值)應等於或大於所示值,且符號相同。
[...]
int
類型的 object 的最大值:INT_MAX +32767
[...]
如果不知道目標/架構細節,這對我們沒有幫助,但是,為了簡化您的問題,讓我們考慮使用固定寬度帶符號整數的示例,並注意以下示例“很好”(在此上下文中):
#include <cstddef>
#include <math.h>
int main() {
double what;
for (int32_t i = 1; i < (int32_t)pow(10, 4); i++)
{
what = (i + i) / (i * i) - i;
}
(void)what;
return 0;
}
而對於我嘗試的特定執行,以下結果導致“浮點異常”(UB;龍可能會飛出我們的鼻子,見下文):
#include <cstddef>
#include <math.h>
int main() {
double what;
for (int32_t i = 1; i < (int32_t)pow(10, 5); i++)
{
what = (i + i) / (i * i) - i;
}
(void)what;
return 0;
}
這里的關鍵是int32_t
的最大值是2,147,483,647
,這意味着i * i
將溢出pow(10, 5)
的大小值。 簽名 integer 溢出是未定義的行為 (UB),從那里開始一切正常。 在這種情況下,UB 很可能巧合地從表達式i * i
的溢出中產生一個值0
,這反過來導致在表達式(i + i) / (i * i)
,更巧合的是,這很可能是浮點數異常的根本情況。
我在這里強調是巧合,因為超出 UB 的任何點都會成為邏輯分析的無用目標; 編譯器供應商可能會假設我們從來沒有 UB 並且一旦我們進入 UB 域就會做任何事情。 我們看到的任何結果都應該被認為是巧合,除非您在特定目標體系結構和硬件上使用 C++ 的某些非標准方言,例如簽名 integer 溢出等特定情況可能被定義為非標准實現定義(和因此由特定的實現指定)而不是 UB。
你的int
溢出是因為 10^14 不適合我見過的任何int
(請注意int
是平台相關的)。 在某些平台上,10^7 已經溢出。 有符號溢出總是導致未定義的行為,有時會導致0
。
std::uint64_t
或double
)來存儲循環變量。pow
。 在循環外計算一次。 for
循環中的i < (long)pow(10, 7)
條件導致 integer (i * i)
表達式變得大於其最大值,從而導致 integer 溢出和未定義的行為。 在某些實現中, i
可能變為0
或1
,導致以下表達式: (i / i)
變為0
。 例如,這反過來可能(在 Visual Studio 中)導致在調試期間出現Integer 除零異常。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.