Cpp: NaN, INF and other numerical exceptions

1. 检查 NaN 数据值 (C/C++/Python 实现)

  NaN 是 Not a Number 的缩写.它是一个数值类型值,通常在浮点计算中,表示未定义或无法表示的值.而且,不能直接使用相等运算符 (==) 检查 NaN.由于在程序中,nan == nan (C/C++/Python) 或 nan is nan (Python) 总是返回 0 或 False.因此,除了采用库函数外,往往可以利用这个性质检查某个数值是否为 NaN.下面介绍如何采用库函数检查 NaN 值:

 

C/C++ 实现

在 C/C++ 中,采用 math.h 标准函数库中的 isnan 宏或函数检查 nan 值,具体示例代码如下:

C 代码 test-nan.c

/* isnan example */
#include <stdio.h>      /* printf */
#include <math.h>       /* isnan, sqrt */

int main()
{
  printf ("isnan(0.0)       : %d\n",isnan(0.0));
  printf ("isnan(1.0/0.0)   : %d\n",isnan(1.0/0.0));
  printf ("isnan(-1.0/0.0)  : %d\n",isnan(-1.0/0.0));
  printf ("isnan(sqrt(-1.0)): %d\n",isnan(sqrt(-1.0)));
  return 0;
}

编译和运行结果,如下所示

$ gcc test-nan.c -lm
$ ./a.out
isnan(0.0)       : 0
isnan(1.0/0.0)   : 0
isnan(-1.0/0.0)  : 0
isnan(sqrt(-1.0)): 1

C++ 代码 test-nan.cpp

/* isnan example */
#include <cmath>       /* isnan, sqrt */
#include <iostream>

using namespace std;

int main()
{
  cout << "isnan(0.0)       : " << isnan(0.0) << endl;
  cout << "isnan(1.0/0.0)   : " << isnan(1.0/0.0) << endl;
  cout << "isnan(-1.0/0.0)  : " << isnan(-1.0/0.0) << endl;
  cout << "isnan(sqrt(-1.0)): " << isnan(sqrt(-1.0)) << endl;

  return 0;
}

编译和运行结果,如下所示

$ g++ test-nan.cpp 
$ ./a.out
isnan(0.0)       : 0
isnan(1.0/0.0)   : 0
isnan(-1.0/0.0)  : 0
isnan(sqrt(-1.0)): 1

如果在编译时增加 -std=c++11 ,采用C++ 2011标准编译程序,可能会出现如下错误:

$ g++ test-nan.cpp -std=c++11
...
error: call of overloaded ‘isnan(double)’ is ambiguous
...

一个简单的解决方法是在所有的 isnan 宏或函数前,增加域操作符( :: ),修改后的示例代码如下:

/* isnan example */
#include <cmath>       /* isnan, sqrt */
#include <iostream>

using namespace std;

int main()
{
  cout << "isnan(0.0)       : " << ::isnan(0.0) << endl;
  cout << "isnan(1.0/0.0)   : " << ::isnan(1.0/0.0) << endl;
  cout << "isnan(-1.0/0.0)  : " << ::isnan(-1.0/0.0) << endl;
  cout << "isnan(sqrt(-1.0)): " << ::isnan(sqrt(-1.0)) << endl;

  return 0;
}

保存后,重新编译运行即可.

 

Python 实现

Python 采用 numpy 数值数学库函数 np.isnan 检查 nan 值,示例代码 test-nan.py 如下:

#!/usr/bin/env python
# -*- coding: utf8 -*-
# author: klchang
from __future__ import print_function

import numpy as np

print ("isnan(0.0)       : ", np.isnan(0.0))
print ("isnan(1.0/0.0)   : ", np.isnan(np.true_divide(1.0, 0.0)))
print ("isnan(-1.0/0.0)  : ", np.isnan(np.true_divide(-1.0, 0.0)))
print ("isnan(sqrt(-1.0)): ", np.isnan(np.sqrt(-1.0)))

运行输出结果,如下:

$ python test-nan.py
isnan(0.0)       :  False
...: RuntimeWarning: divide by zero encountered in true_divide
  print ("isnan(1.0/0.0)   : ", np.isnan(np.true_divide(1.0, 0.0)))
isnan(1.0/0.0)   :  False
...: RuntimeWarning: divide by zero encountered in true_divide
  print ("isnan(-1.0/0.0)  : ", np.isnan(np.true_divide(-1.0, 0.0)))
isnan(-1.0/0.0)  :  False
...: RuntimeWarning: invalid value encountered in sqrt
  print ("isnan(sqrt(-1.0)): ", np.isnan(np.sqrt(-1.0)))
isnan(sqrt(-1.0)):  True

参考资料

1. isnan macro/function - <cmath> reference. http://www.cplusplus.com/reference/cmath/isnan/

2. NaN - Wikipedia, the free encyclopedia. https://en.wikipedia.org/wiki/NaN

3. numpy isnan - NumPy Manual. https://docs.scipy.org/doc/numpy/reference/generated/numpy.isnan.html

4. Why is isnan ambigous and how to avoid it? - stackoverflow. https://stackoverflow.com/questions/33770374/why-is-isnan-ambiguous-and-how-to-avoid-it

 

2. c++中nan,inf详解

nan: not a number 非数字

注意事项:对负数开方sqrt(-1.0)、对负数求对数(log(-1.0))、0.0/0.0、0.0*inf、inf/inf、inf-inf这些操作都会得到nan。(0/0会产生操作异常;0.0/0.0不会产生操作异常,而是会得到nan)

===> #define NaN (0.0/0.0) //_isnan(NaN) is true, but if we use NaN as an integer value, it will devolve into INT_MIN  

辨别方法:isnan() : ture is a nan, false otherwise

isnan(NaN) = true
isnan(Inf) = false
isnan(0.0) = false
isnan(DBL_MIN/2.0) = false
isnan(0.0 / 0.0)   = true
isnan(Inf - Inf)   = true

inf :  infinity 无穷大的数,一般是超过浮点数的表示范围。
注意事项:

1. 1.0/0.0等于inf,-1.0/0.0等于-inf,0.0+inf=inf;

2. 1.0/inf等于0.0

3. inf是可以与其他浮点数进行比较的,即可以参与<=、>+、==、!=等运算。

辨别方法:isinf(): ture is a nan, false otherwise

isinf(NaN) = false
isinf(Inf) = true
isinf(0.0) = false
isinf(exp(800)) = true
isinf(DBL_MIN/2.0) = false

另一个辨别方法:isfinite():ture is a finite value, false otherwise。可用来一起判断inf和nan。


isfinite(NaN) = false
isfinite(Inf) = false
isfinite(0.0) = true
isfinite(exp(800)) = false
isfinite(DBL_MIN/2.0) = true

 

————————————————
版权声明:本文为CSDN博主「sunyoop」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/sunyoop/article/details/79295480

 

3. 对浮点异常值NAN、QNAN、 SNAN、 IND、 INF的处理

最近在写lua的时候,调用C++库,打印了一些异常信息。以前也见过类似的,但是都没管,今天在这里整理,做个记录

32位浮点数在机器中的表示按照IEEE的标准是这样的:
   +------+----------------+-------------------------------+   
   | 1bit |   8bit         |         23bit                 |   
   +------+----------------+-------------------------------+


其中:1bit表示符号位(0表示正,1表示负),8bit表示指数(0~255,实际指数取值还要减去127,即指数取值区间为-127~128),23bit表示尾数。

这里所要说的浮点异常值就是这种表示产生的几种特殊值,IEEE规定根据指数和尾数的不同分别可表示如下几种特殊值:


1. 零值:按上述的浮点表述形式如果指数部分全部为0,并且尾数全部为0,则表示为浮点0.0,并且规定-0 = +0

2. 非规格化值:如果指数全部为0,尾数非0,则表示非规格化的值,16进制看到的就是[80xxxxxx]h或者[00xxxxxx]h

3. 无穷值:如果指数全部为1,尾数全部为0,则根据符号位分别表示正无穷大和负无穷大,16进制看到的就是[FF800000]h或者[7F800000]h

4. NAN:如果指数全部为1,尾数非0,则表示这个值不是一个真正的值(Not A Number)。NAN又分成两类:QNAN(Quiet NAN)和SNAN(Singaling NAN)。QNAN与SNAN的不同之处在于,QNAN的尾数部分最高位定义为1,SNAN最高位定义为0;QNAN一般表示未定义的算术运算结果,最常见的莫过于除0运算;SNAN一般被用于标记未初始化的值,以此来捕获异常


会返回 NaN 的运算有如下三种:

1. 操作数中至少有一个是 NaN 的运算
2. 未定义操作
    下列除法运算:0/0、∞/∞、∞/−∞、−∞/∞、−∞/−∞
    下列乘法运算:0×∞、0×-∞
    下列加法运算:∞ + (−∞)、(−∞) + ∞
    下列减法运算:∞ - (−∞)、(−∞) - ∞
3. 产生复数结果的实数运算。例如:
    对负数进行开方运算
    对负数进行对数运算
    对比-1小或比+1大的数进行反正弦或反余弦运算
那么既然NAN不是一个真实的数值,在程序如何判断变量是否变成了NAN呢?大部分语言中针对NAN值都有一系列的函数定义,C语言中最常见的三个函数:

_isnan(double x);                  //判断是否为NAN
_finite(double x);                  //判读是否为无穷大
_fpclass(double x);                //返回一系列的定义值,如:_FPCLASS_QNAN, _FPCLASS_SNAN
5. INF / inf:这个值表示“无穷大 (infinity 的缩写)”,即超出了计算机可以表示的浮点数的最大范围(或者说超过了 double 类型的最大值)。例如,当用 0 除一个整数时便会得到一个1.#INF / inf值;相应的,如果用 0 除一个负整数也会得到 -1.#INF / -inf值。

6. IND / nan:这个的情况更复杂,一般来说,它们来自于任何未定义结果(非法)的浮点数运算。"IND"是 indeterminate 的缩写,而"nan"是 not a number 的缩写。产生这个值的常见例子有:对负数开平方,对负数取对数,0.0/0.0,0.0*∞, ∞/∞ 等。


这里有个lua下的判断NAN的方法,参考http://snippets.luacode.org/snippets/Test_for_NaN_75


function isnan(x) return x ~= x end
Tests/Usage

if _TEST then -- test suite
assert(isnan(0/0))
assert(not (isnan(math.huge) or isnan(-math.huge)))
assert(not (isnan(nil) or isnan(false) or isnan(0)))
local t = setmetatable({}, {__eq = function() return false end})
assert(not isnan(t))
print 'OK'
end

————————————————
版权声明:本文为CSDN博主「lisai17」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/lisai17/article/details/14649419

 

4. cmath INFINITY

https://en.cppreference.com/w/cpp/numeric/math/INFINITY

Defined in header <cmath>

  

#define INFINITY /*implementation defined*/

 (since C++11)
   

If the implementation supports floating-point infinities, the macro INFINITY expands to constant expression of type float which evaluates to positive or unsigned infinity.

If the implementation does not support floating-point infinities, the macro INFINITY expands to a positive value that is guaranteed to overflow a float at compile time, and the use of this macro generates a compiler warning.

See also

isinf

(C++11)

checks if the given number is infinite
(function)

HUGE_VALFHUGE_VALHUGE_VALL

(C++11)(C++11)

indicates the overflow value for float, double and long double respectively
(macro constant)

has_infinity

[static]

identifies floating-point types that can represent the special value "positive infinity"
(public static member constant of std::numeric_limits<T>)

infinity

[static]

returns the positive infinity value of the given floating-point type
(public static member function of std::numeric_limits<T>)

C documentation for INFINITY

for numerical limits see https://en.cppreference.com/w/cpp/types/numeric_limits

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值