编程中的一些浮点数的问题

1、关于浮点数的取值范围以及精度的问题

根据最广泛采用的IEEE754标准规定,float数据类型长度为32位,其中最高位为符号位,中间8位为指数位,最后23位作为尾数位。

   +------+----------------+-------------------------------+   
   | 1bit    |   8bit               |         23bit                            |   
   +------+----------------+-------------------------------+

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

因此float可以指示的范围(-3.4E+38)~(3.4E+38),这样的数值范围已经很大了基本能够满足我们的需要了,但是有一个问题就是精度的问题,23位的尾数能表示的最大范围是2^23−1=8388607,因此float数的十进制精度只有6-7位,所以在使用的时候要关注其精度。

同理double的尾数由23位扩展到52位,阶码由8位增加到了11位,计算方法不变。其指示范围为-1.7E+308~1.7E+308,其精度则为2^52-1=4503599627370495,为16位,最低可以保证有15位的精度。

2、浮点异常值知识

(引用https://www.cnblogs.com/konlil/archive/2011/07/06/2099646.html)

这里所要说的浮点异常值就是这种表示产生的几种特殊值,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不是一个真实的数值,在程序如何判断变量是否变成了NAN呢?大部分语言中针对NAN值都有一系列的函数定义,C语言中最常见的三个函数:

_isnan(double x);                  //判断是否为NAN

_finite(double x);                  //判读是否为无穷大

_fpclass(double x);                //返回一系列的定义值,如:_FPCLASS_QNAN, _FPCLASS_SNAN,具体参考MSDN

3、C++中的数值范围

C++的 标准库中<limits>中头文件中,包含了不同类型数值极限值,可供我们在编程中使用。

模板类template<> class numeric_limits<>,提供了一下几种静态函数供我们使用

  min                   最小正值(容易和lowest混淆)。

  lowest              最小值。

  max                  最大值。

  epsilon            返回1.0与给定的浮点类型的下一个可表示的值之间的差值。

  round_error    返回给定浮点类型的最大舍入误差。

  infinity            给定类型的无穷大值,可以参与数值比较的。

     NaN包含下面两种:因为其不是真正的值,不能参与数值比较:

       quiet_NaN     静态NaN值,即不会触发异常浮点信号的非数。(注意整型没有非数的概念)

       signaling_NaN 发信号的NaN值,会触发异常浮点信号的非数。

以double为例,进行测试,代码如下:

std::cout<<"double max:"<<std::numeric_limits<double>::max()<<std::endl;
std::cout << "double lowest:" << std::numeric_limits<double>::lowest() << std::endl;
std::cout << "double min:" << std::numeric_limits<double>::min() << std::endl;
std::cout << "double epsilon:" << std::numeric_limits<double>::epsilon() << std::endl;
std::cout << "double round_error:" << std::numeric_limits<double>::round_error() << std::endl;
std::cout << "double infinity :" << std::numeric_limits<double>::infinity() << std::endl;
std::cout << "double quiet Nan :" << std::numeric_limits<double>::quiet_NaN() << std::endl;
std::cout << "double signaling Nan :" << std::numeric_limits<double>::signaling_NaN() << std::endl;

 

结果如下:

posted @ 2019-08-28 17:05  `野百合的春天  阅读(2610)  评论(0编辑  收藏  举报