断了铉 发表于 2018-7-23 03:30:06

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


  其实这篇文章很早就想发出来的,由于工作比较忙碌,所以一直也没写,最近有点空闲时间了,所以趁此整理一下,分享出来。
  今年以来一直在做一个交易所的项目,其中有部分交易的需求需要通过汇总统计来进行数据的聚合筛选,而聚合筛选的数据就是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?!!

  来,把它们都转换成二进制来看看:
  十进制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

  十进制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,不能直接用“==”,必须相减取绝对值!

  特别提醒:
  这绝对不仅仅限于C#,所有的编程语言的double都需要这样去判等,包括js、Python等弱类型语言(浮点型),谨记!

柔柔贝贝 发表于 2018-7-23 03:42:02

路过 帮顶 嘿嘿

endmemory 发表于 2018-7-25 17:01:29

发发呆,回回帖,工作结束~

SUPERNO 发表于 2018-8-1 10:27:33

楼下的接上。。。。

啪啪啪ご 发表于 2018-8-1 17:01:19

我了个去,顶了

学徒君 发表于 2018-8-1 21:25:29

支持,楼下的跟上哈~

suiguofang 发表于 2018-8-2 12:57:47

是爷们的娘们的都帮顶!大力支持

火星恐龙 发表于 2018-8-5 09:35:32

看起来不错

热血虾 发表于 2018-8-6 22:55:42

佩服佩服!

呜咪的天空 发表于 2018-8-9 23:22:38

我是个凑数的。。。
页: [1] 2 3 4 5 6 7 8 9 10
查看完整版本: 由double类型判等引发的一点小思考