简体   繁体   English

为什么代码片段会抛出浮点数异常?

[英]Why does the snippet throw a Floating point exception?

This这个

double what;
for (int i = 1; i < (long)pow(10, 7); i++)
    what = (i + i) / (i * i) - i; 

raises Floating point exception (core dumped).引发浮点异常(核心转储)。 Why?为什么? I'm using clang++.我正在使用 clang++。

Depending on you platform, int is likely 32 or 64 bit wide.根据您的平台, int可能是 32 位或 64 位宽。

From [basic.fundamental]/2 and [basic.fundamental]/3 [extract, emphasis mine]:来自[basic.fundamental]/2[basic.fundamental]/3 [摘录,强调我的]:

[basic.fundamental]/2 [basic.fundamental]/2

There are five standard signed integer types: “ signed char ”, “ short int ”, “ int ”, “ long int ”, and “ long long int ”.有五种标准的有符号 integer 类型:“ signed char ”、“ short int ”、“ int ”、“ long int ”和“ long long int ”。 In this list, each type provides at least as much storage as those preceding it in the list .在此列表中,每种类型提供的存储空间至少与列表中它前面的那些一样多 [...] Plain int s have the natural size suggested by the architecture of the execution environment; [...] plain int具有执行环境架构建议的自然大小; the other signed integer types are provided to meet special needs.提供其他签名integer型号以满足特殊需要。

[basic.fundamental]/3 [basic.fundamental]/3

For each of the standard signed integer types, there exists a corresponding (but different) standard unsigned integer type: “ unsigned char ”, “ unsigned short int ”, “ unsigned int ”, “ unsigned long int ”, and “ unsigned long long int ”, each of which occupies the same amount of storage and has the same alignment requirements as the corresponding signed integer type;对于每个标准的有符号 integer 类型,存在一个对应的(但不同的)标准无符号 integer 类型:“ unsigned char ”、“ unsigned short int ”、“ unsigned int ”、“ unsigned long int ”和“ unsigned long long int ” ”,其中每一个都占用相同的存储量,并且与对应的签名integer类型具有相同的alignment要求; [...] [...]

The signed and unsigned integer types shall satisfy the constraints given in the C standard, section 5.2.4.2.1 .有符号和无符号 integer 类型应满足 C 标准第 5.2.4.2.1 节中给出的约束

We could go to the C11 Standard draft [extract, emphasis mine]:我们可以 go 到C11 标准草案[摘录,强调我的]:

5.2.4.2.1 Sizes of integer types <limits.h> 5.2.4.2.1 integer 类型的大小<limits.h>

[...] Their implementation-defined values shall be equal or greater in magnitude (absolute value) to those shown, with the same sign. [...] 它们的实现定义值的大小(绝对值)应等于或大于所示值,且符号相同。

[...] [...]

  • maximum value for an object of type int : INT_MAX +32767 int类型的 object 的最大值: INT_MAX +32767

[...] [...]

This doesn't help us without knowing target/architectural details, however, so to simplify your questions, let's consider the example using fixed-width signed integers instead, and note that the following example is "fine" (in this context):如果不知道目标/架构细节,这对我们没有帮助,但是,为了简化您的问题,让我们考虑使用固定宽度带符号整数的示例,并注意以下示例“很好”(在此上下文中):

#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;
}

whereas the following results in a "Floating point exception" for the particular executions I have attempted (UB; dragons may fly out of our noses, see below):对于我尝试的特定执行,以下结果导致“浮点异常”(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;
}

The key here is that the maximum value of an int32_t is 2,147,483,647 , which means i * i will overflow for values of the magnitude of pow(10, 5) .这里的关键是int32_t的最大值是2,147,483,647 ,这意味着i * i将溢出pow(10, 5)的大小值。 Signed integer overflow is undefined behaviour (UB), and from there on anything goes .签名 integer 溢出是未定义的行为 (UB),从那里开始一切正常 Likely in this case is that the UB, by coincidence , yields a value 0 from the overflow of the expression i * i , which in turn leads to division by zero (UB again) in the expression (i + i) / (i * i) , which, by further coincidence , is likely to be the root case of the Floating point exception .在这种情况下,UB 很可能巧合地从表达式i * i的溢出中产生一个值0 ,这反过来导致在表达式(i + i) / (i * i)更巧合的是,这很可能是浮点数异常的根本情况。

I'm emphasizing on by coincidence here, as any point beyond UB makes for a useless target for logical analysis;我在这里强调是巧合,因为超出 UB 的任何点都会成为逻辑分析的无用目标; the compiler vendor may assume we never have UB and does anything goes once we've entered the domain of UB.编译器供应商可能会假设我们从来没有 UB 并且一旦我们进入 UB 域就会做任何事情。 Any results we see should be considered coincidental, unless you are working in some non-standard dialect of C++ on a particular target architecture and hardware where eg a particular case such as signed integer overflow may be defined as non-standard implementation-defined (and thus specified by the particular implementation) rather than UB.我们看到的任何结果都应该被认为是巧合,除非您在特定目标体系结构和硬件上使用 C++ 的某些非标准方言,例如签名 integer 溢出等特定情况可能被定义为非标准实现定义(和因此由特定的实现指定)而不是 UB。

Your int overflows because 10^14 fits in no int that I have ever seen (note that int is platform dependent).你的int溢出是因为 10^14 不适合我见过的任何int (请注意int是平台相关的)。 On some platforms, 10^7 will already overflow.在某些平台上,10^7 已经溢出。 Signed overflow always results in undefined behaviour and sometimes results in 0 .有符号溢出总是导致未定义的行为,有时会导致0

  • You might want to use an adequately sized type such as std::uint64_t or double directly to store the loop variable.您可能希望直接使用大小合适的类型(例如std::uint64_tdouble )来存储循环变量。
  • You compute pow for every single loop iteration.您为每个循环迭代计算pow Compute this outside the loop once.在循环外计算一次。
  • Your loop appears to throw away all but the last computation.您的循环似乎丢弃了除最后一次计算之外的所有内容。 Perhaps you could just compute that one?也许你可以计算那个?

The i < (long)pow(10, 7) condition in your for loop causes the integer (i * i) expression to become larger than its maximum value, resulting in integer overflow and undefined behavior . for循环中的i < (long)pow(10, 7)条件导致 integer (i * i)表达式变得大于其最大值,从而导致 integer 溢出和未定义的行为 On some implementations, i might become 0 or 1 , causing the following expression: (i / i) to become 0 .在某些实现中, i可能变为01 ,导致以下表达式: (i / i)变为0 This in turn might (in Visual Studio), for example, result in the Integer Division By Zero exception during the debugging.例如,这反过来可能(在 Visual Studio 中)导致在调试期间出现Integer 除零异常。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM