百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 编程字典 > 正文

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

toyiye 2024-06-21 12:07 10 浏览 0 评论


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

原因分析

我们在现实生活中,数字是以 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的二进制的数据

小数 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

整数2进制转10进制

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

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

1000 010 = (1 * 262 ^ 6) + (0 * 252 ^ 5) + (0 * 242 ^ 4) + (0 * 232 ^ 3) + (0 * 222 ^ 2) + (1 * 212 ^ 1) + (0 * 202 ^ 0) = 64 + 0 + 0 + 0 + 0 + 2 + 0 = 66

小数2进制转10进制

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

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

0.1001 = (1 * 2?12 ^ {-1}) + (0 * 2?22 ^ {-2}) + (0 * 2?32 ^ {-3}) + (1 * 2?42 ^ {-4}) = 0.5 + 0 + 0 + 0.0625 = 0.5625

回到问题: 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。

浮点数存储数字如下:

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

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

V=(?1)s×2E×MV = (-1) ^ s \times 2 ^E \times M

  • S为符号位:表示浮点数的正负(0代表正数,1代表负数);
  • E为指数位:存储指数,该数都会加上一个常数(偏移量),用来表示次方数(需要把二进制的数据转成十进制),长度是11位,取值范围是为0~2047。因为科学计数法中的指数是可以为负数,所以约定减去一个中间数(偏移量)1023,[0,1022] 表示为负,[1024,2047] 表示为正。;
  • M为尾数位:表示有效位(尾数),超出的部分自动进1舍0,默认节省1位有效数字;

例如: 我们有一个二进制的是是这样的, 0 0000 0000 011 110 0000 ……(后面省略45个0) 那么我们可以做成下面的运算: (?1)0×1.11(1.75)×23?1023(-1) ^ 0 \times 1.11(1.75) \times 2 ^{3-1023} (其中0000 0000 011 转成十进制的值是3, 1.11的十进制是1.75) = 1.75×2?10201.75 \times 2 ^{-1020}

表示Infinity

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

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

表示-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)
复制代码

相当于 1.11111……(52个1)×22046?10231.11111……(52个1) \times 2 ^ {2046 - 1023} = Number.MAX_VALUE

表示最小数字

当我们的指数为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}

通过公式: V=(?1)s×2E×MV = (-1) ^ s \times 2 ^E \times M = 20?1023×0.00000000000000……(51个0)1 2 ^ {0 -1023} \times 0.00000000000000……(51个0)1 = 2?1023×2?512 ^ {-1023} \times 2 ^{-51} = 2?10742 {-1074} = Number.MIN_VALUE

表示最大安全整数

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

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

1.111……(此处是52个1)×2?1.111……(此处是52个1) \times 2 ^ ? 这里需要取整数,求 ?, 毫无疑问,问号取52,我们的数字就是整数了。 把小数点去掉就是 一个二进制的 1111……111(总共53个1)= 253?12 ^ {53} - 1 = 9007199254740991 = Number.MAX_SAFE_INTEGER

表示最小安全整数

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

-1111……111(总共53个1)= ?253?1-2 ^ {53} - 1 = -9007199254740991 = Number.MIN_SAFE_INTEGER

引用

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

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

blog.csdn.net/gdhgr/artic…

www.jianshu.com/p/c4bf75048…

安装掘金浏览器插件

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

相关推荐

为何越来越多的编程语言使用JSON(为什么编程)

JSON是JavascriptObjectNotation的缩写,意思是Javascript对象表示法,是一种易于人类阅读和对编程友好的文本数据传递方法,是JavaScript语言规范定义的一个子...

何时在数据库中使用 JSON(数据库用json格式存储)

在本文中,您将了解何时应考虑将JSON数据类型添加到表中以及何时应避免使用它们。每天?分享?最新?软件?开发?,Devops,敏捷?,测试?以及?项目?管理?最新?,最热门?的?文章?,每天?花?...

MySQL 从零开始:05 数据类型(mysql数据类型有哪些,并举例)

前面的讲解中已经接触到了表的创建,表的创建是对字段的声明,比如:上述语句声明了字段的名称、类型、所占空间、默认值和是否可以为空等信息。其中的int、varchar、char和decimal都...

JSON对象花样进阶(json格式对象)

一、引言在现代Web开发中,JSON(JavaScriptObjectNotation)已经成为数据交换的标准格式。无论是从前端向后端发送数据,还是从后端接收数据,JSON都是不可或缺的一部分。...

深入理解 JSON 和 Form-data(json和formdata提交区别)

在讨论现代网络开发与API设计的语境下,理解客户端和服务器间如何有效且可靠地交换数据变得尤为关键。这里,特别值得关注的是两种主流数据格式:...

JSON 语法(json 语法 priority)

JSON语法是JavaScript语法的子集。JSON语法规则JSON语法是JavaScript对象表示法语法的子集。数据在名称/值对中数据由逗号分隔花括号保存对象方括号保存数组JS...

JSON语法详解(json的语法规则)

JSON语法规则JSON语法是JavaScript对象表示法语法的子集。数据在名称/值对中数据由逗号分隔大括号保存对象中括号保存数组注意:json的key是字符串,且必须是双引号,不能是单引号...

MySQL JSON数据类型操作(mysql的json)

概述mysql自5.7.8版本开始,就支持了json结构的数据存储和查询,这表明了mysql也在不断的学习和增加nosql数据库的有点。但mysql毕竟是关系型数据库,在处理json这种非结构化的数据...

JSON的数据模式(json数据格式示例)

像XML模式一样,JSON数据格式也有Schema,这是一个基于JSON格式的规范。JSON模式也以JSON格式编写。它用于验证JSON数据。JSON模式示例以下代码显示了基本的JSON模式。{"...

前端学习——JSON格式详解(后端json格式)

JSON(JavaScriptObjectNotation)是一种轻量级的数据交换格式。易于人阅读和编写。同时也易于机器解析和生成。它基于JavaScriptProgrammingLa...

什么是 JSON:详解 JSON 及其优势(什么叫json)

现在程序员还有谁不知道JSON吗?无论对于前端还是后端,JSON都是一种常见的数据格式。那么JSON到底是什么呢?JSON的定义...

PostgreSQL JSON 类型:处理结构化数据

PostgreSQL提供JSON类型,以存储结构化数据。JSON是一种开放的数据格式,可用于存储各种类型的值。什么是JSON类型?JSON类型表示JSON(JavaScriptO...

JavaScript:JSON、三种包装类(javascript 包)

JOSN:我们希望可以将一个对象在不同的语言中进行传递,以达到通信的目的,最佳方式就是将一个对象转换为字符串的形式JSON(JavaScriptObjectNotation)-JS的对象表示法...

Python数据分析 只要1分钟 教你玩转JSON 全程干货

Json简介:Json,全名JavaScriptObjectNotation,JSON(JavaScriptObjectNotation(记号、标记))是一种轻量级的数据交换格式。它基于J...

比较一下JSON与XML两种数据格式?(json和xml哪个好)

JSON(JavaScriptObjectNotation)和XML(eXtensibleMarkupLanguage)是在日常开发中比较常用的两种数据格式,它们主要的作用就是用来进行数据的传...

取消回复欢迎 发表评论:

请填写验证码