zoukankan      html  css  js  c++  java
  • 组成原理|为什么计算机中0.3 + 0.6 等于 0.899999999...?

    浮点数的不精确性

    打开浏览器控制台 输入 0.3 + 0.6 ,结果输出了0.8999999,不相信你可以按F12打开控制台试一试O(∩_∩)O

    这是为什么?
    我们先看下面的介绍,最后文末会给出答案。

    定点数的表示

    使用BCD编码:用二进制来表示十进制的编码方式

    编码过程:我们用 4 个比特来表示 0~9 的整数,那么 32 个比特就可以表示8个这样的数
    然后我们把最右边的 2 个 0~9 的整数,当成小数部分;
    把左边 6 个 0~9 的整数,当成整数部分。
    这样,我们就可以用 32 个比特,来表示从 0 到 999999.99 这样 1 亿个实数了。

    适用途径:银行、商家精确到“分0.01 ”的交易。
    缺点:浪费比特啊,而且这样的表示方式没办法同时表示很大的数字和很小的数字。

    浮点数的表示

    IEEE的标准,它定义了两个基本的格式:float单精度 和 double双精度

    下面是单精度的表示方法:

    1.符号为表示正负0和1。
    2.指数位,因为我们也需要表示很小的数,指数位置需要负数,所以我们在这里用 1~254 映射到 -126~127 这 254个有正有负的数
    3.有效数位,是一个 23 个比特组成的有效数位。我们用f来表示。

    举了栗子:

    浮点数相加的精度误差

    栗子1:让一个值为 2000 万的 32 位浮点数和 1 相加,你会发现,+1 这个过程因为精度损失,被“完全抛弃”了。

    float a = 20000000.0f;
    float b = 1.0f;
    float sum = a + b;
    print sum //发现sum的值还是2000万,而不是 200000001
    
    

    为什么出现上述情况,因为两个浮点数相加的运算是需要移位的,
    过大或者过小的数移位之后可能会出现有效位数消失的情况,此部分内容可以搜寻相关资料:浮点数相加运算过程、浮点数的二进制表示

    栗子2:将一个等于1.0的浮点数累加循环加2000万次,发现结果是1600万左右,你可以用java实现下面代码,看看结果~~

    为什么?也是浮点数加法产生的精度误差

    
        float sum = 0.0f;
        for (int i = 0; i < 20000000; i++) {
        	float x = 1.0f;
        	sum += x;    	
        }
        print sum // sum 约等于1.6777216E7
    
    

    解决方案:Kahan Summation 算法

    
        float sum = 0.0f;
        float c = 0.0f;
        for (int i = 0; i < 20000000; i++) {
        	float x = 1.0f;
        	float y = x - c;
        	float t = sum + y;
        	c = (t-sum)-y;
        	sum = t;    	
        }
       print sum;//2000万
    

    在每次的计算过程中,都用一次减法,把当前加法计算中损失的精度记录下来然后在后面的循环中,把这个精度损失放在要加的小数上,再做一次运算。
    该算法的数学证明参见:Wikipedia 链接

    所以回到文章开头的问题,0.3 + 0.6 为什么不等于0.9,
    就是因为计算机用浮点数表示法来表示浮点数,只能精确表示 2^x (2的x次方)这种数0.3、0.6不能精确表示出来,例如0.5是2^(-1)是可以被精确表示的。

  • 相关阅读:
    简单易懂dubbo入门实例
    Java中String和byte[]间的 转换
    优秀项目
    Linux下命令行安装weblogic10.3.6
    Linux中VMware虚拟机增加磁盘空间的扩容操作
    office2016_windows永久激活查看方法
    解决eclipse报PermGen space异常的问题
    Ubuntu 18.04上nginx+php环境搭建
    git hook之commit-msg用于检测提交时间是否正确
    maven随记
  • 原文地址:https://www.cnblogs.com/fisherss/p/11049500.html
Copyright © 2011-2022 走看看