1. 首页
  2. 文章列表
  3. 由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等弱类型语言(浮点型),谨记!

文章历史版本:

修改次数:1 次 查看历史版本

版权声明:

本文仅用于学习、研究和交流目的,欢迎非商业性质转载。本文链接:https://masuit.com/1188

l  博主在此发文(包括但不限于汉字、拼音、拉丁字母)均为随意敲击键盘所出,用于检验本人电脑键盘录入、屏幕显示的机械、光电性能,并不代表本人局部或全部同意、支持或者反对观点。如需要详查请直接与键盘生产厂商法人代表联系。挖井挑水无水表,不会网购无快递。

l  文章内容部分来源于互联网,不代表本人的任何立场;涉及到的软件来源于互联网,仅供个人下载使用,请勿用于商业用途,版权归软件开发者所有,下载后请于24小时内删除,请支持正版!因下载本站任何资源造成的损失,全部责任由使用者本人承担!如果你是版权方,认为本文内容对您的权益有所侵犯,请联系博主,待博主进行严格地审查和背景调查后,情况属实的将在三天内将本文删除或修正。

l  博主的文章没有高度、深度和广度,只是凑字数。由于博主的水平不高(其实是个菜B),不足和错误之处在所难免,希望大家能够批评指出。

l  博主是利用读书、参考、引用、抄袭、复制和粘贴等多种方式打造成自己的纯镀 24k 文章,请原谅博主成为一个无耻的文档搬运工!

l  博主只是一名普通的互联网从业者,不懂修电脑,不会卖电脑,不会帮你盗号,不会破解开机密码,找不回你丢失的手机等,如有这样的想法请绕道!

相关推荐:

关于各种开源许可证的详解 java经典面试题——HashMap和HashTable有什么不同?
漫画详解高并发下的HashMap 漫画详解什么是HashMap?
这又是史上最丧心病狂的大数据时代的IT术语解读😂 简单说说State和Status两个单词的区别
IT职场:为什么你总是感觉打码很吃力,总是出低级bug? 一些常用的正则表达式大全

评论区:

    分享按钮