溢出与 Inf

Posted

技术标签:

【中文标题】溢出与 Inf【英文标题】:Overflow vs Inf 【发布时间】:2014-10-27 03:03:36 【问题描述】:

当我在 Matlab 中输入一个大于最大 double 的数字时,大约是 1.79769e+308,例如 10^309,它返回 Inf。出于教育目的,我想获得像 C 编译器那样返回溢出错误消息的溢出异常,而不是 Inf。我的问题是:

    Inf 是溢出异常吗?

    如果是,为什么 C 编译器不返回 Inf

    如果不是,我可以在 Matlab 中得到溢出异常吗?

    Inf 和溢出异常有什么区别吗?

我也不想在 Matlab 中检查 Inf,然后用 error() 函数抛出异常。

【问题讨论】:

@lakesh 你是什么意思? @lakesh 我不想计算。 1e^309 也不正确。我想你的意思是10^309=1.0e309 为什么要这样做?检查 Inf 然后抛出异常有什么问题? 这是一个有效且有趣的问题。那些拒绝投票或投票结束的人应该阅读how the floating-point spec deals with infinity 并溢出。它们通常混合在一起,就像在 Matlab 中一样,但两者并不相同。 我也不明白反对票。这是一个完全有效的问题,而且我真的很好奇! 【参考方案1】:

1) C/C++ 中的浮点数

对floating-point numbers 的操作可能会产生不是数值的结果。例子:

运算的结果是一个复数(想想sqrt(-1.0)) 操作的结果未定义(想想1.0 / 0.0) 运算结果太大而无法表示 在其中一个操作数已经是 NaN 或 Inf 的情况下执行操作

IEEE754 的哲学是to not trap 这样exceptions 默认情况下,但要产生特殊值(InfNaN),并允许计算正常继续而不会中断程序。用户可以自行测试这些结果并分别处理它们(如 MATLAB 中的 isinfisnan 函数)。

存在two types of NaN 值:NaN(安静 NaN)和 sNaN(信号 NaN)。通常浮点数的所有算术运算在运算不能成功完成时都会产生静默类型(不是信令类型)。

control 浮点环境和catch FP 异常有(平台相关的)函数:

Win32 API 有 _control87() 来控制 FPU 标志。 POSIX/Linux 系统通常 handle FP exception 通过捕获 SIGFPE 信号(请参阅 feenableexcept)。 SunOS/Solaris 也有自己的功能(参见 Sun/Oracle 的 Numerical Computation Guide 中的第 4 章) C99/C++11 引入了 fenv 标头,其中包含控制浮点异常标志的函数。

比如看看Python是如何实现不同平台的FP异常控制模块的:https://hg.python.org/cpython/file/tip/Modules/fpectlmodule.c

2) C/C++ 中的整数

这显然与浮点数完全不同,因为整数类型不能表示 Inf 或 NaN:

无符号整数使用modular arithmetic(如果结果超过最大整数,则值会环绕)。这意味着无符号算术运算的结果始终是“数学定义的”并且永远不会溢出。将此与使用 saturation arithmetic 表示整数的 MATLAB 进行比较(uint8(200) + uint8(200) 将是 uint8(255))。 另一方面,有符号整数溢出是undefined behavior。 integer division by zero 是未定义的行为。

【讨论】:

【参考方案2】:

浮点数

MATLAB implements IEEE Standard 754 用于浮点运算。 本标准定义了五个例外:

    无效操作 除以零 溢出 下溢 不准确

如GNU C Library 所述,这些异常由状态字指示,但不会终止程序。 而是返回一个依赖于异常的默认值;该值可以是实际数字或特殊值 MATLAB 中的特殊值有Inf-InfNaN-0;这些 MATLAB 符号用于代替官方标准保留的二进制表示,以提高可读性和可用性(有点漂亮的语法糖)。 对特殊值的操作定义明确,操作直观。

有了这些信息,问题的答案是:

    Inf 表示执行的操作引发了上述异常之一(即 1、2 或 3),并且Inf 被确定为默认返回值。

    根据C 程序的编写方式、正在使用的编译器以及存在的硬件,INFINITY and NaN 是可以由C 操作返回的特殊值。这取决于是否以及如何实施 IEEE-754 标准。 C99 将 IEEE-754 实现作为标准的一部分,但最终由编译器决定实现的工作原理(这可能会因激进的优化和舍入模式等标准选项而变得复杂)。

    返回值Inf-Inf 表示发生了溢出异常可能,但也可能是无效操作或被零除。我认为 MATLAB 不会告诉您它是什么(尽管您可能可以通过编译的 MEX 文件访问该信息,但我不熟悉这些)。

    见答案 1。

如需更多有趣和深入的示例,请here is a nice PDF。

整数

整数在 MATLAB 中的行为与上述不同。 如果对指定位大小的整数的操作将超过该类的最大值,则它将被设置为最大值,反之亦然,用于负数(如果有符号)。 换句话说,MATLAB 整数不会换行。

【讨论】:

【参考方案3】:

我将重复“MATLAB Answers”网站上Jan Simon 的回答:

要在除零时停止(在调试器模式下),请使用:

warning on MATLAB:divideByZero
dbstop if warning MATLAB:divideByZero

类似地停止取零的对数:

warning on MATLAB:log:LogOfZero
dbstop if warning MATLAB:log:LogOfZero

若要在操作(函数调用或赋值)返回NaNInf 时停止,请使用:

dbstop if naninf

不幸的是,前两个警告似乎是 no longer supported,尽管最后一个选项在 R2014a 上仍然适用于我,实际上是 documented。

【讨论】:

还有see this question and answers 和这个post from Undocumented Matlab 在捕捉警告。

以上是关于溢出与 Inf的主要内容,如果未能解决你的问题,请参考以下文章

内存溢出与内存泄露知识点总结

数值溢出与精度损失

内存溢出与内存泄漏区别

内存溢出与jvm参数配置

Java学习---内存泄露与溢出的区别

缓冲区溢出实验与基础