浮点数的范围和精度问题(从原理到结论)

浮点数的范围和精度问题(float和double的比较)

  今天遇到一道C++题,非常简单,就是比较两个浮点数是否相等。我的第一思路就是输入两个double类型的变量a,b,看a-b的绝对值是否小于 1e8 ,是则相等。

  但是!!!问题并没有到这里结束,我去瞄了一眼其他人的解法,发现居然可以输入float类型的变量,然后直接用逻辑判断==就可以了,然后在线测评也通过了,也是非常神奇。于是对float和double类型的范围和精度产生了兴趣,为啥误差精度为 1e8 时float类型的数就能直接判断,而double却不行呢?
  到网上搜罗到了一些解答,本文对其进行了归纳整理。

  1. 关于浮点数的精度与取值范围的问题
  2. float的范围和有效数字怎么算出来的?
  3. float与double的范围和精度
  4. float和double的精度
  5. 维基百科 IEEE 754标准(二进制浮点数算术标准)

   这首先得从浮点数在计算机中的表示和存储方式说起。
  
   根据IEEE标准,浮点数是通过科学计数法来存储的,比如120.5用十进制的科学计数法来表示就是 1.205×102 ,但是计算机中所有数据都是用二进制存储的,所以得先转换为二进制数,即 1.1110001×26

  
   浮点数在计算机中的存储分为三个部分:
   1. 符号位(sign):float和double符号位均为1位,0代表正数,1代表负数
   2. 指数位(exponent):存储科学计数法中的指数部分,采用移位存储
   3. 尾数位(fraction):存储科学计数法中的尾数部分

  根据IEEE 754标准,单精度float类型使用32比特存储,其中1位表示符号,8位表示指数,23位表示尾数;双精度double类型使用64比特存储,1位符号位,11位指数位,52位尾数位。
  然后再来讲讲移位存储。拿float来举例,内存中使用32位来存储float浮点数,其中第1位表示浮点数正负,第2~9位表示指数,后23位表示指数。表示指数的8位二进制虽然连续,但并不在同一字节中(实际上是由第一字节的后7位和第二字节的第1位组成),然后这8位指数位的第1位也是用来表示正负……然后我就没怎么弄懂了,欢迎大家赐教。总之如果按照移位存储,指数值最后需要加上偏移值127就对了。
  

浮点数的范围

  后来发现在头文件float.h里其实已经解释的很清楚了(所以说没事多翻翻源码总是没错的):




float能够表示的最大值为 3.40×1038 ,最小区分精度约为 1.19×107 (这一点和最开始那道题目有点矛盾,等我尝试几组数据之后再补充)。



float能够表示的最大值为 1.80×10308 ,最小区分精度约为 2.22×1016

不过这宏定义的最大最小值感觉并不是我们所认为的“不溢出内存的情况下所能表示的最大数字”,我现在也说不清,留个问题之后慢慢琢磨好了。

浮点数的精度

  这个解释起来轻松一点,精度这里指的是最大有效数字的位数,即只需要考虑尾数部分就可以啦。
  对于float类型,尾数部分是23,转换成10进制的精度, 223=10x –> x=23log26.92 ,所以23位2进制最多只能表示6位10进制数,这里就是头文件中FLT_DIG=6的来由。
  但还有一种说法,也是网上的主流说法,二进制小数点的第一位永远都是1,可以省略,实际上二进制的精度为24,所以10进制的精度为7。

猜你喜欢

转载自blog.csdn.net/qq_16137569/article/details/79508091