[英]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.