找回密码
 立即注册
查看: 31634|回复: 100

由double类型判等引发的一点小思考

    [复制链接]
  • TA的每日心情
    慵懒
    2021-11-26 16:44
  • 签到天数: 488 天

    连续签到: 1 天

    [LV.9]妙领天机

    488

    主题

    3011

    回帖

    4611

    积分

    如雷贯耳

    积分
    4611
    发表于 2018-7-23 03:30:06 | 显示全部楼层 |阅读模式

    马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

    您需要 登录 才可以下载或查看,没有账号?立即注册

    ×

      其实这篇文章很早就想发出来的,由于工作比较忙碌,所以一直也没写,最近有点空闲时间了,所以趁此整理一下,分享出来。
      今年以来一直在做一个交易所的项目,其中有部分交易的需求需要通过汇总统计来进行数据的聚合筛选,而聚合筛选的数据就是double类型的,我当然知道double类型进行判等的时候会有点坑,直到后来,有些业务需要其他同事来协同,然后就有个同事问我代码里面,写的if(Math.Abs(x-y)<=1E-7)是什么意思,SQL语句里面也这样写的,类似于这样的:
      double[]
      price = { 0.1, 0.2, 0.3, 0.8, 0.5 };
      double sum = 1.9;
      if (Math.Abs(sum - price.Sum()) <= 1E-7)
      {
      //todo
      }
      我解释说:double类型可能会有精度溢出的情况,导致在判等的时候会有丢失精度的问题,直接用“==”判等不行,所以就需要相减取绝对值再判断小于等于0.00000001的就认为它们是相等的。
      因为这个细节上的问题,公司让我新出的面试题我也加进去了,但最后评审的时候说这道题涉及到的不仅仅是C#的知识点,万一人家没学过计算机组成原理那不整来瓜起了,所以又把这道题剔除了。


      其实要究其真正原因,那还是得从计算机组成原理讲起。
      我们知道double双精度类型有53 位有效数字精度(包含符号号),并总共占用8字节。
      程序里面我们处理的大多是十进制,而计算机处理直接收二进制数据,学过进制转换的童鞋肯定知道整数都可以完美地进行进制间的转换,而double是小数,小数的进制转换就会出现循环小数的情况,而double的位数有限,就导致了十进制小数转二进制时出现了精度丢失的情况。
      经典案例:0.1+0.2-0.3=5.551115123125783e-17?。
      why?0.1+0.2-0.3居然不等于0?!!
    87c01ec7gy1fsq11586mvj208c08c3yh.jpg

      来,把它们都转换成二进制来看看:
      十进制0.1
      >二进制0.00011001100110011…(循环0011)
      >尾数为1.1001100110011001100…1100(共52位,除了小数点左边的1),指数为-4(二进制移码为00000000010),符号位为0
      >计算机存储为:0 00000000100 10011001100110011…11001
      > 因为尾数最多52位,所以实际存储的值为0.00011001100110011001100110011001100110011001100110011001
      再看看十进制0.2
      >二进制0.0011001100110011…(循环0011)
      >尾数为1.1001100110011001100…1100(共52位,除了小数点左边的1),指数为-3(二进制移码为00000000011),符号位为0
      >存储为:0 00000000011 10011001100110011…11001
      因为尾数最多52位,所以实际存储的值为0.00110011001100110011001100110011001100110011001100110011
    87c01ec7gy1fsq115j89bj204d014we9.jpg

      十进制0.3
      >按照上面相同的套路,得出来:0.0011001100110011001100110011001100110011001100110011,结尾的0011循环。
      那么两者相加得: 0.00011001100110011001100110011001100110011001100110011001+0.00110011001100110011001100110011001100110011001100110011=0.01001100110011001100110011001100110011001100110011001100
      也就是说只要0.3在最低位加一的话就和0.2+0.1一样了,而尾数的最低位是第52位,再乘上-2的阶码,就是2的负54次方,这个数刚好就是:5.551115123125783e-17。
      所以如果要判等0.1+0.2-0.3和0,不能直接用“==”,必须相减取绝对值!
    87c01ec7gy1fsq115voutj205102pweb.jpg
      特别提醒:
      这绝对不仅仅限于C#,所有的编程语言的double都需要这样去判等,包括js、Python等弱类型语言(浮点型),谨记!
    楼主热帖
    [!luckypost!]: 一个袋子砸在了 断了铉 头上,断了铉 赚了 8 金钱. !lucky_goodrank! / !lucky_badrank!
  • TA的每日心情
    慵懒
    2019-8-30 15:02
  • 签到天数: 469 天

    连续签到: 3 天

    [LV.9]妙领天机

    5

    主题

    3086

    回帖

    3094

    积分

    声名显赫

    积分
    3094
    发表于 2018-7-23 03:42:02 | 显示全部楼层
    路过 帮顶 嘿嘿
    回复

    使用道具 举报

  • TA的每日心情
    开心
    2019-8-30 12:49
  • 签到天数: 468 天

    连续签到: 6 天

    [LV.9]妙领天机

    4

    主题

    3045

    回帖

    3050

    积分

    声名显赫

    积分
    3050
    发表于 2018-7-25 17:01:29 | 显示全部楼层
    发发呆,回回帖,工作结束~
    回复

    使用道具 举报

  • TA的每日心情

    2019-8-29 18:19
  • 签到天数: 462 天

    连续签到: 2 天

    [LV.9]妙领天机

    0

    主题

    3140

    回帖

    3140

    积分

    声名显赫

    积分
    3140
    发表于 2018-8-1 10:27:33 | 显示全部楼层
    楼下的接上。。。。
    回复

    使用道具 举报

  • TA的每日心情
    开心
    2019-8-30 16:45
  • 签到天数: 464 天

    连续签到: 8 天

    [LV.9]妙领天机

    0

    主题

    3099

    回帖

    3093

    积分

    声名显赫

    积分
    3093
    发表于 2018-8-1 17:01:19 | 显示全部楼层
    我了个去,顶了
    回复

    使用道具 举报

  • TA的每日心情
    奋斗
    2019-8-30 16:26
  • 签到天数: 475 天

    连续签到: 1 天

    [LV.9]妙领天机

    10

    主题

    3029

    回帖

    3043

    积分

    声名显赫

    积分
    3043
    发表于 2018-8-1 21:25:29 | 显示全部楼层
    支持,楼下的跟上哈~
    回复

    使用道具 举报

  • TA的每日心情
    难过
    2019-8-30 19:44
  • 签到天数: 456 天

    连续签到: 2 天

    [LV.9]妙领天机

    2

    主题

    3071

    回帖

    3072

    积分

    声名显赫

    积分
    3072
    发表于 2018-8-2 12:57:47 | 显示全部楼层
    是爷们的娘们的都帮顶!大力支持
    回复

    使用道具 举报

  • TA的每日心情
    擦汗
    2019-8-30 15:14
  • 签到天数: 484 天

    连续签到: 1 天

    [LV.9]妙领天机

    1

    主题

    3087

    回帖

    3087

    积分

    声名显赫

    积分
    3087
    发表于 2018-8-5 09:35:32 | 显示全部楼层
    看起来不错
    回复

    使用道具 举报

  • TA的每日心情
    开心
    2019-8-30 19:33
  • 签到天数: 475 天

    连续签到: 1 天

    [LV.9]妙领天机

    6

    主题

    3136

    回帖

    3141

    积分

    声名显赫

    积分
    3141
    发表于 2018-8-6 22:55:42 | 显示全部楼层
    佩服佩服!
    回复

    使用道具 举报

  • TA的每日心情
    奋斗
    2019-8-30 05:55
  • 签到天数: 471 天

    连续签到: 2 天

    [LV.9]妙领天机

    9

    主题

    3084

    回帖

    3100

    积分

    声名显赫

    积分
    3100
    发表于 2018-8-9 23:22:38 | 显示全部楼层
    我是个凑数的。。。
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|Archiver|手机版|小黑屋|任逍遥

    GMT+8, 2024-11-22 20:15 , Processed in 0.065016 second(s), 52 queries .

    Powered by 任逍遥 X3.5

    Copyright © 2001-2024, Rxiaoyao Cloud.

    快速回复 返回顶部 返回列表