如何理解 0.1+0.2
0.1 + 0.2 = 0.3
这是很多人都知道的事,但是,你的程序往往告诉你:
0.1 + 0.2 = 0.30000000000000004
不信你试试
那么,为什么?
你应该知道,十进制的 2,用二进制表示就是 10
这也是计算机存储 2 的方式
也就是我们需要两个“位”:一个位存 1,另一个存 0
用两个“位”,可以存四个数字,他们是:
- 00(十进制的 0)
- 01(十进制的 1)
- 10(十进制的 2)
- 11(十进制的 3)
我们买的 u 盘,经常说,是“2G 的”、“8G的”、“128G的”
而且我们都知道,“8G”的,比“2G”的存得多
但再多,也有个“限度”,总有装满的时候
所谓 8 G,就是说,这个 u 盘有 8000 M,或者 8 * 1024 M
也就是 8,000,000 K,或者 8 * 1024 * 1024 K
而 1 K,有八个“位”,就是上面说的那个“位”,
所以,8 G,就有 8,000,000 * 8 个“位”,或者 8 * 1024 * 1024 * 8 个“位”
两个位,可以存四个数字,那 8 G 呢?
很多,但不是无限多
也就是说,再大的存储器(不论是 u 盘、硬盘、内存条……)也只能表示“有限个”数字
但,有多少个数字?
无限个,这个无限,不仅仅是十、百、千、万、十万……这样向上增长
也有 0.1, 0.11, 0.111, 0.1111, 0.11111 ……这种小数
你会发现,-1
到 0
之间,就有无数个“数”
那计算机怎么用有限的存储器,表示无限的数呢?
整数还好,常用的整数的范围不大
我们只需要 64 个位,就可以表示 2 的 64 次方个数字
即 18,446,744,073,709,552,000 个数字
你能想象什么场景下,能用到这么大的数吗
而几十块钱一个的 u 盘,竟然有 64,000,000 个位
但,-1
到 0
之间有无数个“小数”啊
无奈,计算机只能用近似值来存小数
所以,你会发现,计算机认为:
0.111111111111111111111111111111
和
0.1111111111111111111111111111111111111111111
是“相等的”!
因为,对这俩数,计算机都会“偷工减料”
只存前面的 n 位
因为:
- 后面的位太小了,不重要(借口)
- 没有能力存全部(真正原因)
虽然是借口,但我们人类还是接受了
毕竟我们人类在大部分情况下,允许极小的误差
回到最初的问题,0.1 + 0.2 = ?
当我们说 0.1 的时候,我们一般说的是十进制的 0.1,即十分之一,即 1/10
那么二进制的 0.1,是多少?当然是“二分之一”,即 1/2
可能你觉得有些别扭,你可以这么想一下(十进制中):
- 十个 10 加起来,等于 100
- 十个 1 加起来,等于 10
- 十个 0.1 加起来,等于 1
那么在二进制中:
- 10 + 10 = 100
- 1 + 1 = 10
- 0.1 + 0.1 = ?
我想,你应该知道了,十进制中的 0.1 和 二进制中的 0.1 不相等
我们的问题0.1 + 0.2 = ?
中的 0.1 显然是十进制中的 0.1
那么转化为二进制,是……?
不管是多少,我们先给它起个名字:“奤”
先考虑一个问题,3/10 是多少?
0.333333333333333333333333333333……
二进制中,也有这样的数,奤就是其中一员
上面说了,计算机只认识“有限”个数
奤这种,小数点后面有无穷无尽个 0、1,电脑肯定不认识
电脑只认识奤的近似值
也就是,当你写下 0.1 时,电脑只存了个 0.1 的近似值!
不幸的是,0.2 也是个奤
所以,当你让电脑算 0.1 + 0.2 = ?
时
它只是把“0.1 的近似值”加上“0.2 的近似值”
这怎么可能得到准确的结果?
那……
- 为什么 0.1 + 0.1 就能得到准确的结果?
- 0.1 为什么是个奤?
如果你对这俩问题感兴趣,可以留个言
因为我不确定写这么多字,是不是真有人感兴趣,如果真有的话,会继续写的
如何理解 0.1+0.2相关推荐
- 深度理解do{} while(0)语句的作用
深度理解do{} while(0) 在linux内核中常常会看到do{} while(0)这样的语句,有人疑惑,认为无意义,因为他只执行一次,加不加do{} while(0)小过失完全一样的,那你就错 ...
- JS魔法堂:彻底理解0.1 + 0.2 === 0.30000000000000004的背后
Brief 一天有个朋友问我"JS中计算0.7 * 180怎么会等于125.99999999998,坑也太多了吧!"那时我猜测是二进制表示数值时发生round-off error所 ...
- 图卷积神经网络(GCN)理解与tensorflow2.0代码实现
图(Graph),一般用 G=(V,E)G=(V,E)G=(V,E) 表示,这里的VVV是图中节点的集合,EEE 为边的集合,节点的个数用NNN表示.在一个图中,有三个比较重要的矩阵: 特征矩阵XXX ...
- JS魔法堂:彻底理解0.1 + 0.2 === 0.30000000000000004的背后 1
Brief 一天有个朋友问我"JS中计算0.7 * 180怎么会等于125.99999999998,坑也太多了吧!"那时我猜测是二进制表示数值时发生round-off error所 ...
- 理解OAuth 2.0(转)
From: http://www.mamicode.com/info-detail-1610036.html 理解OAuth 2.0 作者: 阮一峰 日期: 2014年5月12日 OAuth是一个关于 ...
- [转载]理解OAuth 2.0
原文地址:http://www.ruanyifeng.com/blog/2014/05/oauth_2_0.html 理解OAuth 2.0 作者: 阮一峰 OAuth是一个关于授权(authoriz ...
- C语言之对 0, ‘0‘ , \0 以及 “0“ 的理解
刚开始学习c语言时对这块不是很了解,非常困惑,后来随着学习的深入,终于明白了其中的不同,希望以下文章能对你有所帮助. 0是个整型字符,类似于1,2,3这样的整型.单引号括起来的是字符常量,只能有一个字 ...
- 理解OAuth 2.0
理解OAuth 2.0 作者: 阮一峰 日期: 2014年5月12日 OAuth是一个关于授权(authorization)的开放网络标准,在全世界得到广泛应用,目前的版本是2.0版. 本文对OAut ...
- 深入理解Linux进程调度(0.4)
学习方法论 写作原则 标题括号中的数字代表完成度与完善度 0.0-1.0 代表完成度,1.1-1.5 代表完善度 0.0 :还没开始写 0.1 :写了一个简介 0.3 :写了一小部分内容 0.5 :写 ...
- 深入理解 Android 9.0 Crash 机制(二)
极力推荐Android 开发大总结文章:欢迎收藏 Android 开发技术文章大总结 本篇文章主要介绍 Android 开发中的部分知识点,通过阅读本篇文章,您将收获以下内容: 九. AppError ...
最新文章
- HTML5 本地文件操作之FileSystemAPI整理(二)
- Set Matrix Zeroes leetcode
- CTF Geek Challenge——第十一届极客大挑战Web Write Up
- Mysql 8 密码策略之组件方式及ERROR 1819
- cl_ibase_ibintx_buf buffer class
- 福禄克OFP光纤测试仪5个强大的功能
- c语言cis,c语言小白学习历程第五篇
- pytorch搭建TextRCNN模型与使用案例
- Visual C# 2005 - 如何于DataGridView控件中以跨数据行方式显示数据
- Java 用POST方式 传对象给 Servlet
- php+crontab+shell方案实现的秒级定时发起异步请求回调方案
- [CareerCup] 12.6 Test an ATM 测试一个自动取款机
- ibm7945服务器引导盘,IBM ServerGuide引导盘全系列|IBM引导盘
- 手机管理服务器文件夹,手机管理服务器文件夹
- 研发团队管理实践总结
- java设计模式(1)
- 11款常用的安全测试工具
- AMP Roadshow技术分享路演中国专场报名
- 使用第三方sdk时问题
- 启动keepalived报错(VI_1): received an invalid passwd!
热门文章
- html style属性的用法
- 由错误<note: candidate expects 1 argument, 0 provided>引发的思考
- 华为HCIE认证改版(2021年5月30日正式改版升级)
- IE-LAB网络实验室:华为AAA认证详解
- cocos creator(12)
- FFplay文档解读-31-视频过滤器六
- 假装接入阿里云---PC运行mqtt.fx
- 《数据结构(c++语言版)》 清华大学邓俊辉
- 7-111 福到了 (15 分)(c语言)
- 提升睡眠质量的助眠好物,拥有这些,不再担忧睡眠质量