一个数字截取引发的精度问题(四)
这篇是精度问题的最后一篇,要是想看前面的,请看微信历史记录。
做前端的都感觉JS这语言巨坑无比,兼容性让你摸不到头脑,甚至还会让你脱发。一些初学者遇到:
0.1 + 0.2 = 0.30000000000000004
都会觉得这JS太TM坑了,一个小数计算都不会。可是我想说,这"锅"JS不背!其实和JS采用的数值存储 IEEE754 规范有关,所有采用此规范的语言都会有此问题并不是JS的"锅"。
IEEE754
IEEE浮点数算术标准(IEEE 754)是最广泛使用的浮点数运算标准,为许多CPU与浮点运算器所采用,单精确度(32位)、双精确度(64位)、延伸单精确度(43位以上,很少使用)与延伸双精确度(79位元以上,通常以80位元实做)
计算机中是用有限的连续字节保存浮点数的。 JS采用64位(双精度)存储数据,在 IEEE 标准中,浮点数是将所有二进制位分割为特定宽度的符号域(S),指数域(E)和尾数域(F)三个域, 其中保存的值分别用于表示给定二进制浮点数中的符号,指数和尾数。
根据国际标准IEEE 754,任意一个二进制浮点数V可以表示成下面的形式:
V = (-1)^s×M×2^E
- (-1)^s表示符号位,当s=0,V为正数;当s=1,V为负数。
- M表示有效数字,大于等于1,小于2,但整数部分的1可以省略。
-
2^E表示指数位。
对于十进制的5.25对应的二进制为:101.01,相当于:
1.0101*2^2
。所以,S为0,M为1.0101,E为2。 而-5.25=-101.01=-1.0101*2^2
。所以S为1,M为1.0101,E为2。
复习一下十进制转二进制:
口诀
整数部分除2取余,由下到上;小数部分乘2取整,由上到下。
0.1 在计算机中如何存储?
首先 0.1 转化为二进制:0.000110011(0011循环)套用公式可得:
(-1)^0*1.1001*2^-4
所以 s:0,M:1.1001(循环1001),E:-4。
由于小数位仅储存 52bit, 储存时会将超出精度部分进行"零舍一入",
无限精确值:
1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001
实际储存值:
1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1010
此处精度已经丢失一次。最后0.1实际存储为:
0.0001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1010
同理计算出0.2的实际存储值(同样也存在精度丢失):
0.001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1010
两数相加得:
0.01001100110011001100110011001100110011001100110011001110
再转为十进制:0.30000000000000004。
在线转换工具:http://tool.oschina.net/hexconvert。
- org.springframework.data.redis.serializer.SerializationException: Cannot serialize;
- 样式化加载失败的图片
- 使用telnet命令验证邮箱(r4笔记第19天)
- Spring+SpringMVC+MyBatis+easyUI整合进阶篇(十二)Spring集成Redis缓存
- 前端开发中的字符编码
- 算法工程师的面试难不难,如何准备?-图像处理/CV/ML/DL到HR面总结
- Spring+SpringMVC+MyBatis+easyUI整合进阶篇(九)Linux下安装redis及redis的常用命令和操作
- 通过使用hint unnest调优sql语句(r4笔记第38天)
- Spring+SpringMVC+MyBatis+easyUI整合进阶篇(十一)redis密码设置、安全设置
- 极简增强学习新手教程 返回专栏查看评论
- 经典Java面试题收集
- 百度魅族深度学习大赛初赛冠军作品(图像识别.源码)
- easyUI整合富文本编辑器KindEditor详细教程(附源码)
- 经典Java面试题收集(二)
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- iOS开发之CryptoKit
- koroFileHeader更新日志
- 掌握浏览器重绘(reflow)重排(repaint)-前端进阶
- var和let/const的区别
- 刷新/关闭页面之前发送请求
- Web Beacon 刷新/关闭页面之前发送请求
- 解决django无法访问本地static文件(js,css,img)网页里js,cs都加载不了
- python3 logging日志封装实例
- 解决Python中报错TypeError: must be str, not bytes问题
- H5 notification浏览器桌面通知
- Android线程池控制并发数多线程下载
- Android progressbar实现带底部指示器和文字的进度条
- js 调用栈机制与ES6尾调用优化介绍
- Android Fragment实现列表和内容联动
- 前端中等算法-无重复字符的最长子串