当没有浮点数据类型时,为啥这段代码会出现浮点异常?

Posted

技术标签:

【中文标题】当没有浮点数据类型时,为啥这段代码会出现浮点异常?【英文标题】:Why does this code get floating point exception when there is no float data-type?当没有浮点数据类型时,为什么这段代码会出现浮点异常? 【发布时间】:2018-07-11 22:14:04 【问题描述】:

我没有除以零,并且我的代码中没有浮点数据类型,我仍然得到浮点异常。

#include <cmath>
#include <cstdio>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;


int main() 
    unsigned long long int t,n;

    cin>>t;
    while(t--)
    
        cin>>n;
        unsigned long long int deno = pow(10,n-1),count=2,sum = 0,f1=1,f2=1;

         while(1)
            sum = f1+f2;
            f1 = f2;
            f2 = sum;
            count++;
            if((int)(sum/deno)>0)
                cout<<count<<endl;
                 break;
              
        

    
    return 0;

之前的所有问题都有类似的除以零的问题,但变量 deno 永远不能像n&gt;=2那样为零。

我之前的研究:

    “Floating point exception” in code that contains no floats Floating Point Exception C++ Why and what is it?

问题说明:https://www.hackerrank.com/contests/projecteuler/challenges/euler025/problem

它通过了 2 个测试用例,失败了 2 个。都是隐藏的测试用例。 Result image

通过输入 1 50 我们可以重现错误。详情:

 GDB trace: Reading symbols from solution...done. [New LWP 15127] Core
 was generated by `solution'. Program terminated with signal SIGFPE,
 Arithmetic exception.
 #0  main () at solution.cc:23 
 23 if((int)(sum/deno)>0)
 #0  main () at solution.cc:23

【问题讨论】:

浮点执行是当您尝试除以 0 或取模时。它不是浮点独有的 重现问题需要多长时间?当我运行您的代码时,它会一直运行。 使用你的调试器。观察deno 的值,看看它是否为零。 如果您不知道导致问题的输入,@Yılmazedis 调试不会轻易提供帮助。 您是否意识到unsigned long long 只能上升大约 19 位,而问题需要 5000?即使是long double 也只能达到 308 位(当然会出现浮点错误)。您将需要一种新方法。 【参考方案1】:

整数除法会产生异常,在某些平台(例如 Linux)上报告为“浮点异常”是完全正常的。你可以很容易地从整数除以零得到它,或者,另一个例子,通过触发溢出,如

int i = INT_MIN;
int b = -1;
i = i / b;

http://coliru.stacked-crooked.com/a/07c5fdf47278b696

在某些情况下,此异常可能会根据优化级别出现或消失。该异常通常仅在编译器决定生成实际除法指令(而不是优化除法)时触发。


在您的情况下,使用了无符号整数除法,因此除以零似乎是唯一可能的罪魁祸首。我猜这个

unsigned long long int deno = pow(10,n-1);

恰好在deno 中产生零。 pow 是一个产生浮点结果的浮点函数。如果原始值太大(n 等于 50 就是这种情况),从浮点类型转换为整数类型会导致未定义的行为。请注意,即使目标整数类型是无符号的也是如此。

【讨论】:

谢谢,但是我应该如何更改我的代码来解决这个问题? 感谢您深入研究问题并帮助我解决问题 是的,刚刚检查了1 50 deno0。然而,在 Visual Studio 上是 9223372036854775808。这确实是UB。 编写自己的 pow() 函数。 std::pow 总是转换整数并返回浮点结果。仅在标准库中没有整数的等价物。网络上有许多 int 等价物。 n>=19 的逻辑在各种平台上都是错误的。它只是溢出了 long long 的 64 位边界。

以上是关于当没有浮点数据类型时,为啥这段代码会出现浮点异常?的主要内容,如果未能解决你的问题,请参考以下文章

为啥 main() 函数不返回浮点值?

为啥我会收到“浮点异常(核心转储)”?

为啥浮点数据类型在没有类型转换 4.7 的情况下在此代码中不起作用? [复制]

在java中的double和float类型数据相除为啥可以除以零

为啥会产生浮点异常?

JAVA 将浮点类型的字符串转换成整数类型 (出现转换异常)