zoukankan      html  css  js  c++  java
  • 为什么浮点数计算,会得到一个不精确的值

    为什么浮点数计算,会得到一个不精确的值

    一、总结

    一句话总结:

    就像10进制中无法准确表示1/3,二进制中无法准确表示1/10,而计算机只认识二进制,而且能表示的位数有限,所以这样10进制->2进制->10进制的过程中会出现误差

    二、为什么浮点数不能精确表示?

    转自或参考:为什么浮点数不能精确表示?_Java__lxyzk的博客-CSDN博客
    https://blog.csdn.net/lzyzk/article/details/49949061

    我们知道,在编写程序时,两个浮点数(floatdouble)不能直接进行大小比较。
    当然,我们也都知道,不能直接进行大小比较的原因是因为浮点数在计算机内部不能精确的表示。可是,为什么在计算机内部浮点数不能够精确地表示呢?

    这还得从IEEE 754标准说起。

    从IEEE 754标准说起

    根据IEEE 754标准,浮点数在计算机内部存储时主要分为符号位(sign)、指数(exponent)部分、尾数(fraction)部分:

    浮点数整体

    那么,这个数就是:

    (1)sign×2exponent×fraction2

    例如十进制的0.5可以表示成(1)0×21×1.0

    以32位的单精度浮点数(常见的float)为例,它的符号位占一位(bit),指数部分占8位,尾数部分占23位。

    现在我们需要存储十进制的0.1这个小数,首先需要把0.1转换成二进制数。然而,我们会发现,十进制的0.1转换成二进制是一个无限循环小数:0.0001100110011001100…

    可是,尾数只有23位,只能截取二进制小数的前23位存储。这时,误差就产生了。

    当再次把这个浮点数转换成十进制数时,由于损失了一些二进制位,转换回来的十进制数自然也就与原来的不同了。

    即使是有11位指数和52位尾数的64位双精度浮点数,也不可能精确存储一个无限循环小数,只能是相对单精度浮点数而言,存储的精度更高。

    问题扩展–看懂IEEE 754

    看懂IEE 754标准之前,首先需要了解一下定点数的表示。

    定点数

    所谓定点数,就是小数点位置固定不动的小数。

    例如二进制的0.10可以表示成10。

    虽然计算机不能表示出小数点,但是这里我们假设小数点就在最前面,于是,任何小于1且大于等于0的小数都可以用定点数来表示。

    例如:001表示的是二进制小数0.001。

    浮点数

    相对于定点数,小数点的位置不固定的数就叫做浮点数。由于浮点数的小数点位置不固定,因此,就需要一定的方法来表示小数点的位置。

    现在的计算机主要采用的是IEEE 754标准来表示浮点数。

    IEEE 754标准的浮点数存储

    事实上,在浮点数的存储过程中,为了运算方便和尽可能多的提高存储存储空间的利用效率,往往不会直接存储各部分的二进制原码。

    例如,指数部分存储的是实际指数值得移码,而尾数部分存储的是规约化后的尾数的补码。

    所谓移码,就是将实际的指数值加上一个固定的数值而得到的数。在单精度浮点数中这个数是127,在双精度浮点数中这个数是1024。假设这个数是e,则e的计算公式如下:

    e=2n11

    其中n 是指数部分的长度。

    如此一来,即使是最小的指数(例如单精度浮点数是-126),在存储的时候也会存储为1(-126+127)。这样,就方便了指数的大小比较也省了一个符号位。

    现在,上面的浮点数的计算公式就变成了下面的样子:

    (1)sign×2exponente×fraction2

    当然,这还不是计算公式的最终形态,因为我们还有尾数没有说。

    刚刚在上面提到过定点数的表示其实就是在这里做一下铺垫。因为,尾数部分实际上存储的就是一个定点数。

    这里的定点数需要时一个以1开头的二进制数并且小数点位于第一位数的后面。

    (0.5)10 来说,把它转换成二进制是(0.1)2=(1)0×(1.0)2×21

    把指数部分用移码表示就是1+127=126 ,所以,0.5的就存储为:

    0 01111110 1000000000000000000000

    现在我们又发现,既然尾数部分的定点数都是1开头,那就把这个1给省略掉好了。这样就又多出一位来保存尾数,提高精度了(当然,省略开头的第一个1后,默认小数点的位置就变成现在的第一位数之前了)。

    于是乎,上面的0.5在实际存储中就变成了

    0 01111110 0000000000000000000000

    此时,最终形态的计算公式就是:

    (1)sign×2exponente×(fraction2+1)

    当指数部分为0,而尾数部分不为0(指数、尾数同时为0表示的当然是数字0)时,这个浮点数称为非规约形式浮点数IEEE 754标准规定:非规约形式的浮点数的指数偏移值比规约形式的浮点数的指数偏移值大1。

     
     
     
  • 相关阅读:
    ArcGIS 添加 MarkerSymbol 弹出“图形符号无法序列化为 JSON”错误
    C#中为特定类型增加扩展方法
    C# 访问Oracle数据库
    SQL Server2012中时间字段为DateTime和VarChar的区别
    Visual Studio2012调试时无法命中断点
    Prism框架研究(三)
    Prism框架研究(二)
    WPF Path总结(一)
    性能测试 -- 服务器参数调整
    eclipse-->run as --> maven test 中文乱码
  • 原文地址:https://www.cnblogs.com/Renyi-Fan/p/12324661.html
Copyright © 2011-2022 走看看