重温js—— 数字的存储,js精度问题

简介: 我们在现实生活中,数字是以 10 进制(0,1,2,3,4,5,6,7,8,9)的形式来进行数学运算, 但是在计算机中是以 2 进制( 0,1)的数据进行存储的。那么10 进制与 2 进制是怎么进行转换的呢?

在js中,数字是如何存储的,为啥在小数相加的时候,会出现精度不准确。如:


8f17e6142a3be782e31d689cf2578d5e.png


原因分析


我们在现实生活中,数字是以 10 进制(0,1,2,3,4,5,6,7,8,9)的形式来进行数学运算, 但是在计算机中是以 2 进制( 0,1)的数据进行存储的。那么10 进制与 2 进制是怎么进行转换的呢?


整数10进制转2进制


十进制在转二进制,将十进制的数据除以2,得出余数和商,然后继续用商来除以2,知道商为0,得到所有的余数。


例如: 将十进制的10转成二进制的数据是 1010


表达式 余数
10 / 2 5 0
5 / 2 2 1
2 / 2 1 0
1 / 2 0 1


然后把余数反过来读, 1010 就是 10的二进制的数据


cc7c8016168b4712f6ead7cbeaab76e6.png


小数 10进制 转 2 进制


将10进制的小数部分乘以2,然后判断结果的小数部分是否为0,为0结束,不为0继续乘以2


例如: 将十进制的10.25转成二进制的数据是 1010.01


表达式 小数部分 整数部分
0.25 * 2 0.5 .5 0
0.5 * 2 1.0 0 1


然后把整数部分是结果自上而下获取结果 01 就是 10进制的0.25


68e285014ddaeb2a53cf3eb3d4f370da.png


整数2进制转10进制


二进制的整数转成十进制是,从右往左 的每个数字 乘以 2n2^{n} (n >=0 && n < 字符串长度-1),然后将每一位的和进行相加。


例如: 将二进制的 1000 010 转成十进制 66


ec0a2a93341743bd9347f6173cefbda1.png

15d533f1a4faa80b52b1f9b9aff85782.png


小数2进制转10进制


二进制的小数转十进制是从小数点从左往右的每个数字乘以2−n2^{-n} (n >=1 && n <= 字符串长度-1),然后将每一位的和进行相加。


例如将1000 010.1001转成10进制的数是


5728453e8ea34ee7b161c756cb2e9bd3.png


回到问题: 0.1 + 0.2 这是十进制的数字,在做运算的时候需要转成二进制来进行运算。


0.1转二进制的数据如下:


表达式 小数部分 整数部分
0.1 * 2 0.2 .2 0
0.2 * 2 0.4 .4 0
0.4 * 2 0.8 .8 0
0.8 * 2 1.6 .6 1
0.6 * 2 1.2 .2 1
0.2 * 2 0.4 .4 0
0.4 * 2 0.8 .8 0
0.8 * 2 1.6 .6 1
0.6 * 2 1.2 .2 1

… 此处是 0011无限循环,所以得出的结果是 0.0 0011 0011 0011 ……





0.1 转换的成二进制的小数是无限循环小数,但是我们的计算机保存的二进制的数据是有限的位数, 而 js中存储数据的长度是固定为 64位 ,所以这下明白了,为啥有的小数相加会出现问题了吧。


数字存储的方式


每种语言都有不一样的存储方式,例如: 整数法,浮点法等。但是在 js中,存储的数据的方式是使用浮点法。


浮点法存放的数字,叫做浮点数(float),浮点数分位单精度和双精度。 JS中,使用双精度存放浮点数,来源 IEEE 754。


浮点数存储数字如下:


bc512cb2fc044dc0f48e1edb11bbd13b.png


上图是64位的双精度浮点数,最高位是符号位S(sign),中间的11位是指数E(exponent),剩下的52位为尾数(有效数字)M(mantissa)


浮点数科学计数法 根据IEEE 754标准,任意一个浮点数的二进制都可以用如下公式进行表示:


44beb9e72fcc47ee9bd5b58024547824.png


  • S为符号位:表示浮点数的正负(0代表正数,1代表负数);


  • E为指数位:存储指数,该数都会加上一个常数(偏移量),用来表示次方数(需要把二进制的数据转成十进制),长度是11位,取值范围是为0~2047。因为科学计数法中的指数是可以为负数,所以约定减去一个中间数(偏移量)1023,[0,1022] 表示为负,[1024,2047] 表示为正。;


  • M为尾数位:表示有效位(尾数),超出的部分自动进1舍0,默认节省1位有效数字;


a469a963edae6fbec5964bededc1c56b.png

9fe73b147b7c4a249c55fccbea7139fe.png


表示Infinity


现在我们知道了数字的存储方式,那么我们Infinity是怎么样表示的呢?


Infinity : 0 1111111111 0000000000……………………=Infinity 
只要我们的指数最大,后面的数字是 1.00000……(此处是52个0)  那就规定是 Infinity
复制代码

79d4aeaf2c351ae81bd78471431b36dc.png


表示-Infinity


同理,我们也可以知道最小的-Infinity数字的表示方式


Infinity : 1 1111111111 0000000000……………………= -Infinity 
只要我们的指数最大,后面的数字是 1.00000……(此处是52个0)  前面符号位是负数,那就是规定是-Infinity
复制代码


表示NaN


还有一个就是NaN是咋样表示的呢?


Infinity : 0 1111111111 101010……………………= NaN
只要我们的指数最大(2047),后面的尾数随便,表示的就是NaN
复制代码


表示最大数字


当我们的指数是 2046(1111111110)然后尾数全是1 那么这个就是最大的数字


 1 1111111110 111111……………………(52个1)
复制代码

ec852ddd00584037b53106787c6ed426.png

1163540f6f599398e2ed0ebcfc839dc2.png


表示最小数字


当我们的指数为0 (0000 0000 000), 然后尾数 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0001,这个时候最小。


 0 00000000000 000000000000000000000000000000000000000000000000001
复制代码


0.0000000000000000000000000000000000000000000000000001 转换成十进制特别小,所以我们就姑且 默认为 2−51 2 ^ {-51}


4a7a4cc6fd204ce9803347547a7445a8.png

10e925bec9638ccf063616a7c3cec55f.png


表示最大安全整数


那么如何表示最大的安全整数呢?(安全整数是连续的数字,就是说该数字从1到它和它的下一位存在并且是连续的)


想要是一个连续数字,那就是尾数取满,全是1, 指数来取整数


208af6e8d3bf4b248bed9966b252104c.png

78b9a4a8ae07f0f9d1e21334087849b3.png


表示最小安全整数


同理,最小的安全整数我们只要保证符号位是1就行


eba8d91b2ce64960b365dcc946f06a6c.png

29387cbdf1d17cc93b5cfc8138885093.png


引用


这篇文章是我找遍全网的资料,然后经过大量的测试得出的一个结果。感谢那些前辈,站在巨人的肩膀上,加油!!!


developers.weixin.qq.com/community/d…


blog.csdn.net/gdhgr/artic…


www.jianshu.com/p/c4bf75048…



安装掘金浏览器插件


打开新标签页发现好内容,掘金、GitHub、Dribbble、ProductHunt 等站点内容轻松获取。快来安装掘金浏览器插件获取高质量内容吧!

相关文章
|
5月前
|
关系型数据库 MySQL 存储
|
4月前
|
存储 中间件 API
Nest.js 实战 (六):使用 Session 在不同请求间存储信息
这篇文章介绍了在Nest.js中如何使用Session来记录客户状态。文章首先解释了Session的概念,然后详细说明了如何在Nest.js中安装和使用express-session,包括全局配置、参数说明、使用方式和常用方法。
|
5月前
|
存储 前端开发 安全
JavaScript进阶 - 浏览器存储:localStorage, sessionStorage, cookies
【7月更文挑战第2天】探索Web存储:localStorage持久化,sessionStorage会话限定,cookies则伴随HTTP请求。了解它们的特性和限制,如localStorage的5MB容量限制、跨域问题,sessionStorage的生命周期,及cookies的安全与带宽消耗。使用时需权衡安全、效率与应用场景。示例代码展示存储与检索方法。
317 2
|
6月前
|
存储 JavaScript 前端开发
JavaScript中的对象是数据结构,存储键值对,键为字符串,值可为任意类型,包括函数(作为方法)
【6月更文挑战第25天】JavaScript中的对象是数据结构,存储键值对,键为字符串,值可为任意类型,包括函数(作为方法)。
41 2
|
6月前
|
存储 JavaScript 前端开发
JavaScript中的数组是核心数据结构,用于存储和操作序列数据
【6月更文挑战第22天】JavaScript中的数组是核心数据结构,用于存储和操作序列数据。创建数组可以使用字面量`[]`或`new Array()`。访问元素通过索引,如`myArray[0]`,修改同样如此。常见方法包括:`push()`添加元素至末尾,`pop()`移除末尾元素,`shift()`移除首元素,`unshift()`添加到开头,`join()`连接为字符串,`slice()`提取子数组,`splice()`进行删除、替换,`indexOf()`查找元素位置,`sort()`排序数组。还有其他如`reverse()`、`concat()`等方法。
131 2
|
5月前
|
存储 JavaScript 前端开发
JavaScript进阶 - 浏览器存储:localStorage, sessionStorage, cookies
【7月更文挑战第8天】Web开发中的客户端存储技术,如`localStorage`, `sessionStorage`和`cookies`,用于保存用户设置和跟踪活动。`localStorage`持久化存储,`sessionStorage`随页面会话消失。两者提供基本的增删查改操作,但有大小限制和安全风险。`cookies`适合会话管理,可设置过期时间并能跨域。使用时注意存储量、安全性和跨域策略,选择适合场景的存储方式。
214 0
|
7月前
|
存储 SQL JavaScript
js常见的存储API以及应用场景?使用方式,各个优缺点?
【4月更文挑战第4天】JavaScript存储API包括`localStorage`、`sessionStorage`、`cookies`、`IndexedDB`和弃用的`Web SQL`。`localStorage`和`sessionStorage`用于页面数据存储,前者持久化,后者限当前会话。`cookies`适用于会话管理,但存储空间有限。`IndexedDB`适合大量结构化数据存储和查询。废弃的`Web SQL`曾提供关系型数据库功能。选择时需考虑数据性质、存储需求、安全性和兼容性。
117 2
|
7月前
|
存储 JavaScript 前端开发
在浏览器中存储数组和对象(js的问题)
在浏览器中存储数组和对象(js的问题)
68 0
|
存储 JavaScript
JS数据类型有哪些?存储上有什么区别?
JS数据类型有哪些?存储上有什么区别?
|
7月前
|
存储 JavaScript 前端开发
数组:数组是JS中的一种特殊对象,用于存储一组有序的数据。需要掌握数组的创建、访问、修改以及各种内置方法。
数组:数组是JS中的一种特殊对象,用于存储一组有序的数据。需要掌握数组的创建、访问、修改以及各种内置方法。
76 2