zoukankan      html  css  js  c++  java
  • 浮点数精度对编程使用的影响

    浮点数在计算机编程中一定会使用,然而使用中会有很多坑。最近做机械臂就被跳到坑里了。机械臂三自由度反解出来的cos值比1大一点点,1.00000...4。就是这一点点,坑了我一晚上,坑了师兄一上午。计算公式没问题,求解程序没问题,就是算出来的值有问题!后来才反应到是浮点数存储造成的。

    举一个最简单的浮点数存储影响的例子。

    double targetValue = 0.21;
    double counter = 0;
    int main()
    {
        while(counter != targetValue)
        {
            counter += 0.01;
        }
        return 0;
    }

    上面的程序,按照我们想想的,while循环将执行21次,之后counter和targetValue相等,循环结束。

    但是事实上,运行的时候并不是这样。这里我截取几个vs调试的变量值来说明。

    首次进入循环前,可以看到targetValue的值并不是我们设置的0.21,而是0.20999...

     

    在每次相加时,counter也不是加0.01,而是和0.01差距很小的一个数,经过20次相加之后并不是0.2,而有差距。

     

    当相加21次时,两个数并不相等,所以无法退出循环。

     

    可以看出,浮点数并不如我们认为的那么精确。实际上,造成这个的原因是因为计算机的存储机制造成的。计算机使用二进制存储数据,那么对于0.21这个数,下面是转换的过程,乘二取整法。

    0.21*2=0.42 整数为0 -> 0.0

    0.42*2=0.84 整数为0 -> 0.00

    0.84*2=1.68 整数为1 -> 0.001

    0.68*2=1.36 整数为1 -> 0.0011

    0.36*2=0.72 整数为0 -> 0.00110

    最后可以表示为:

    0.0011010111000010…

    可以看出,转换成二进制之后,是一个无限的数,不能精确的表示出来。所以就造成了这个bug。这也是我们程序中,cos算出来超过1一点点的原因。我在matlab里还原了c++的算法,matlab计算出的数值就是1,没有任何小数。

    对于上面比较的问题,很多人都知道解决方法,那就是两个浮点数求差,差值很小就认为相等。程序如下:

    double targetValue = 0.21;
    double counter = 0;
    int main()
    {
        while(fabs(counter - targetValue) > 1e-5)
        {
            counter += 0.01;
        }
        return 0;
    }

    关于cos计算的bug,我最后采取的手段是将浮点数保留5位小数,精度能够符合我们的要求,而且不会被浮点数存储影响。

    计算机上的坑真的多,争取毕业前多踩,多填坑。

  • 相关阅读:
    asp.net core的DI框架思考以及服务实例的获取方式总结
    并发相关随笔(持续更新)
    为什么Dotnet Core的DI默认是在控制器中注入
    在控制台下玩玩dotnet core内置原生的DI
    asp.net core 依赖注入实现全过程粗略剖析(3)
    EF 下如何更新数据表数据
    asp.net core 依赖注入实现全过程粗略剖析(2)
    asp.net core 依赖注入实现全过程粗略剖析(1)
    【MongoDB 高可用篇】MongoDB Sharding Cluster启动和关闭过程
    【MongoDB 高可用篇】MongoDB Sharding Cluster集群环境搭建
  • 原文地址:https://www.cnblogs.com/huipengly/p/8423316.html
Copyright © 2011-2022 走看看