广告
返回顶部
首页 > 资讯 > 前端开发 > JavaScript >JavaScript中Number类型常见误区如何解决
  • 620
分享到

JavaScript中Number类型常见误区如何解决

2024-04-02 19:04:59 620人浏览 独家记忆
摘要

这篇“javascript中Number类型常见误区如何解决”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们

这篇“javascript中Number类型常见误区如何解决”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“JavaScript中Number类型常见误区如何解决”文章吧。

在 JavaScript 中数值只有一种,即 Number 类型,内部表示为双精度浮点型,即其他语言中的 double 类型,所以在 JavaScript 中实际上是没有整数类型的,数值都是按浮点数来处理的,存储方法相同,遵循 IEEE 754 国际标准。因此,在 JavaScript 中 3 和 3.0 被视为同一个值:

3.0 === 3 // true

对于整数情况,能够准确计算的整数范围为在−253-2^{53}−253 ~ 2532^{53}253 之间,不包含两个端点,只要在这个范围内整数可以放心使用。除了十进制以外整数还可以通过八进制或十六进制的字面值来表示,其中八进制字面值的第一位必须是零,其次是八进制数字序列(0 ~ 7),如果字面值中的数值超出范围,那么前导零将被忽略,后面的数值被当作十进制解析,这儿需要注意在严格模式中八进制的这种表示会报错,es6中进一步明确,八进制的表示要使用前缀0o,示例:

(function(){
  console.log(0o11 === 011)
})()
// true
// 严格模式
(function(){
  'use strict';
  console.log(0o11 === 011)
})()
// Uncaught GyntaxError

十六进制字面值前两位必须是 0x,后跟任何十六进制数字(0 ~ 9以及A ~ F),其中 A ~ F 可以大写,也可以小写。ES6中又扩展了二进制的写法,使用前缀0b(或0B)。

前面我们对 JavaScript 运行时中的 Number 类型进行了简单介绍,接下来正式开始介绍这些常见问题,不过首先我们需要了解 Number 类型的数据存储方式:

一、存储方式

JavaScript 中的 Number 类型使用的是双精度浮点型,即其他语言中的 double 类型,双精度浮点数使用 8 个字节即 64bit 来进行存储,现代计算机中浮点数大多是以国际标准 IEEE 754 来存储,存储过程分两步,

  • 把浮点数转换为对应的二进制数,并用科学计数法表示

  • 将转换之后的数通过 IEEE 754 标准表示成真正会在计算机存储的值。

根据 IEEE 754 标准任何一个二进制浮点数 V 都可以表示成:

JavaScript中Number类型常见误区如何解决

JavaScript中Number类型常见误区如何解决

举个例子,十进制的 5.0,写成二进制是 101.0,相当于 1.01∗221.01 * 2^21.01∗22,其中 S=0,M=1.01,E=2。

IEEE 754规定对于32位浮点数最高1位是符号位S,接下来8位是指数E,剩下的23位为有效数字M,具体如下图所示:

JavaScript中Number类型常见误区如何解决

对于64位的浮点数最高1位是符号位S,接下来11位是指数E,剩下的52位是有效数字M,具体如下图所示:

JavaScript中Number类型常见误区如何解决

注意:IEEE754 对于有效数字M和指数E还有一些特别的规定。

前面说过,1 <= M < 2,也就是说 M 总是可以写成 1.xxxxxxx 的形式,其中 xxxxxxx 表示效数部分。IEEE 754 规定,在计算机内部保存 M 时默认这个数的第一位总是1,因此可以被舍去,只保存后面的 xxxxxxx 部分。比如保存1.01的时候只保存01,等到读取的时候再把第一位的1加上去,这样做的目的就是为了节省一位有效数字,以32位浮点数为例,留给有效数字M的只有23位,将第一位的1舍去以后等于保存24位有效数字。

至于指数E,情况较为复杂。首先,E为一个无符号指数,这意味着,如果E为8位,它的取值范围为 0 ~ 255,如果E为11位,它的取值范围为0 ~ 2047。但是我们知道科学计数中的E是是可以出现负值的,所以IEEE 754规定,E的真实值必须再减去一个中间数,对于8位的E,这个中间数是127,对于11位的E,这个中间数是1023。

比如2102^{10}210的E是10,所以保存成32位浮点数时,必须保存成 10+127=137,即 10001001。

然后指数E还可以分成三种情况:

  • E不全为0或不全为1:这时,浮点数就采用上面的规则表示,即指数E的计算值减去127(或1023),得到真实值,再将有效数字M前加上第一位的1。

  • E全为0:这时,浮点数的指数E等于1 ~ 127(或1 ~ 1023),有效数字M不再加上第一位的1,而是还原成0.xxxxxxx的小数,这样做是为了表示±0,以及接近0的很小的数字。

  • E全为1:这时,如果有效数字M全为0,表示±无穷大(正负取决于符号位S);如果有效数字M不全为0,表示这个数不是一个数(NaN)。

示例:浮点数 9.0 如何用二进制表示?还原成十进制又是多少?

首先,浮点数 9.0 等于二进制的 1001.0,即 1.001∗231.001 *2^31.001∗23

那么,第一位的符号位 S=0,有效数字 M 等于 001 后面再加 20 个 0,凑满 23 位,指数 E 等于 3+127=130,即 10000010。

所以,写成二进制形式,应该是 S+E+M,即0 10000010 001 0000 0000 0000 0000 0000。这个 32 位的二进制数,还原成十进制,正是 1091567616。

注:虽然在 JavaScript 中无论是小数还是整数都是按照64位的浮点数形式存储,但是进行整数运算会自动转换为32位的有符号整数,例如位运算,有符号整数使用31位表示整数的数值,用第32位表示整数的符号,数值范围是−231-2^{31}−231 ~ 2312^{31}231。

二、浮点数运算的精度丢失

问题缘由

众所周知在 JavaScript 中 0.1+0.2 不等于 0.3,实际上所有浮点数值存储遵循 IEEE 754 标准的编程语言中都会存在这个问题,这是因为计算机中小数的存储先是转换成二进制进行存储的,而 0.1、0.2 转换成二进制分别为:

(0.1)10 => (00011001100110011001(1001)...)2 (0.2)10 => (00110011001100110011(0011)...)2

可以发现,0.1 和 0.2 转成二进制之后都是一个无限循环的数,前面提到尾数位只能存储最多 53 位有效数字,这时候就必须来进行四舍五入了,而这个取舍的规则就是在 IEEE 754 中定义的,0.1 最终能被存储的有效数字是

0001(1001)(1001)(1001)(1001)(1001)(1001)(1001)(1001)(1001)(1001)(1001)(1001)101 + (0011)(0011)(0011)(0011)(0011)(0011)(0011)(0011)(0011)(0011)(0011)(0011)(0011)01 = 0100(1100)(1100)(1100)(1100)(1100)(1100)(1100)(1100)(1100)(1100)(1100)(1100)111

最终的这个二进制数转换成十进制的就是 0.30000000000000004 ,这儿需要注意,53 位的存储位指的是能存 53 位有效数字,因此前置的 0 不算,要往后再取到  53 位有效数字为止。

因此,精度丢失的问题实际上用一句话概括就是计算机中用二进制存储小数,而大部分小数转成二进制后都是无限循环的值,因此存在取舍问题,也就是精度丢失。

解决办法

ES6 在 Number 对象上新增了一个极小常量:Number.EPSILON,值为 2.220446049250313e-16,引入这么一个常量就是为了为浮点数计算设置一个误差范围,如果这个误差小于 Number.EPSILON 我们就认为得到了准确结果。

三、大整数的运算精度丢失及溢出

问题缘由

在介绍问题的具体缘由之前我想先给大家介绍一下所谓最大安全整数范围以及最大数字绝对值的范围是如何得到的?

JavaScript 能够表示的数字的绝对值范围是 5e-324 ~ 1.7976931348623157e+308,这两个取值可以通过 Number.MIN_VALUE 和 Number.MAX_VALUE 这两个字段来表示,如果某次计算的结果得到了一个超出 JavaScript 数值范围的,那么这个数值会自动被转换为特殊的 Infinity 值,具体来说,如果这个数是负数,则会被转换成 -Infinity(负无穷),如果这个数值是正数,则会被转换成 Infinity(正无穷)。

示例:

console.log(Number.MAX_VALUE) // 1.7976931348623157e+308
console.log(Number.MIN_VALUE) // 5e-324
console.log(Number.MAX_VALUE + Number.MAX_VALUE) // Infinity

那么这个取值范围是如何得到的呢?

前面说到 JavaScript 中数值的保存采用的是双精度浮点型,遵循 IEEE 754 标准,在 ECMAScript 规范中规定指数 E 的范围在 -1074 ~ 971,双精度浮点型中有效数字 M 的存储位为52,但是有效数字 M 由于可以省略第一位1,节省一个存储位,因此有效数字M可以存储的范围为 1 ~ 2532^{53}253,因此 JavaScript 中 Number 能表示的最大数字绝对值范围是 2−10742^{-1074}2−1074 ~ 253+9712^{53+971}253+971。

注:通过 Number.isFinite()(ES6引入)和 isFinite() 方法可以判断一个数值是不是有穷的,即如果参数位于最小与最大数值之间时会返回 true。

让我们回归主题,为什么会出现大整数的运算精度丢失及溢出呢?

JavaScript 中最大安全整数的范围是 −253-2^{53}−253 ~ 2532^{53}253,不包括两个端点,即 -9007199254740991 ~ 9007199254740991,可以通过 Number.MIN_SAFE_INTEGER 和 Number.MAX_SAFE_INTEGER 字段查询,超出这个范围的整数计算都是不准确的,例如:

console.log(Number.MAX_SAFE_INTEGER) // 9007199254740991
console.log(Number.MIN_SAFE_INTEGER) // -9007199254740991
console.log(9007199254740991 + 2) // 9007199254740992

最大安全整数9007199254740991对应的二进制数如图:

JavaScript中Number类型常见误区如何解决

53位有效数字都存储满了之后,想要表示更大的数字,就只能往指数数加一位,这时候尾数因为没有多余的存储空间,因此只能补0。

JavaScript中Number类型常见误区如何解决

如图所示,在指数位为53的情况下,最后一位尾数位为0的数字可以被精确表示,而最后一位尾数位为1的数字都不能被精确表示。也就是可以被精确表示和不能被精确表示的比例是1:1。

同理,当指数为54的时候,只有最后两位尾数为00的可以被精确表示,也就是可以被精确表示和不能被精确表示的比例是1:3,当有效位数达到 x(x>53) 的时候,可以被精确表示和不能被精确表示的比例将是1 : 2^(x-53)^ - 1。

可以预见的是,在指数越来越高的时候,这个指数会成指数增长,因此在 Number.MAX_SAFE_INTEGER ~ Number.MAX_VALUE 之间可以被精确表示的整数可以说是凤毛麟角。

之所以会有最大安全整数这个概念,本质上还是因为数字类型在计算机中的存储结构。在尾数位不够补零之后,只要是多余的尾数为1所对应的整数都不能被精确表示。

可以发现,不管是浮点数计算的计算结果错误和大整数的计算结果错误,最终都可以归结到js的精度只有53位(尾数只能存储53位的有效数字)。

解决办法

那么我们在日常工作中碰到这两个问题该如何解决呢?

大而全的解决方案就是使用 mathjs,看一下 mathjs 的输出:

math.config({
    number: 'BigNumber',      
    precision: 64 
});
console.log(math.fORMat(math.eval('0.1 + 0.2'))); // '0.3'
console.log(math.format(math.eval('0.23 * 0.34 * 0.92'))); // '0.071944'
console.log(math.format(math.eval('9007199254740991 + 2'))); 
// '9.007199254740993e+15'

以上就是关于“JavaScript中Number类型常见误区如何解决”这篇文章的内容,相信大家都有了一定的了解,希望小编分享的内容对大家有帮助,若想了解更多相关的知识内容,请关注编程网JavaScript频道。

--结束END--

本文标题: JavaScript中Number类型常见误区如何解决

本文链接: https://www.lsjlt.com/news/98968.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • JavaScript中Number类型常见误区如何解决
    这篇“JavaScript中Number类型常见误区如何解决”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们...
    99+
    2022-10-19
  • Python中常见的错误类型及解决方案
    Python中常见的错误类型及解决方案在使用Python进行编程的过程中,我们经常会遇到各种各样的错误。这些错误可能是因为我们的代码有误,也可能是由于运行环境或依赖库的问题。了解这些错误类型及其解决方案对于我们提高编程效率和调试能力非常重要...
    99+
    2023-10-22
    语法错误 逻辑错误 解决方案: 错误类型: 异常错误
  • PHP中常见的错误类型及如何调试和解决
    在 PHP 开发中,经常会遇到各种错误。了解和熟悉常见错误类型,以及如何进行调试和解决这些错误,是每个 PHP 开发人员值得掌握的技能。本文将介绍一些常见的 PHP 错误类型,并提供具体的代码示例和解决方法。语法错误语法错误是 PHP 开发...
    99+
    2023-10-21
    调试 错误类型 解决
  • PHP中常见错误类型及其解决方法【总结】
    PHP是一门广泛应用于Web开发、服务器脚本编程的编程语言,具有易学易用、扩展性强、高效稳定等优点。但是在PHP开发过程中,程序员难免会遇到各种各样的错误,下面我们来看一下PHP中常见的错误类型及其解决方法。1. 语法错误语法错误是最常见的...
    99+
    2023-05-14
    php
  • PHP中常见错误类型及其解决方法是什么
    本篇内容介绍了“PHP中常见错误类型及其解决方法是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!1. 语法错误语法错误是最常见的错误之一...
    99+
    2023-07-05
  • PHP7中的类型声明:如何避免常见的类型错误?
    PHP7中引入了严格的类型声明,这是一个重要的改进,可以帮助开发者在开发过程中更早地捕获类型错误,并减少因类型错误而引起的bug。本文将介绍PHP7中的类型声明以及如何避免常见的类型错误。一、类型声明的介绍在PHP7中,我们可以使用类型声明...
    99+
    2023-10-22
    PHP 类型错误 类型声明
  • GO编程中常见的数据类型错误及其解决方法
    在GO编程中,数据类型错误常常是程序出现问题的主要原因之一。本文将介绍GO编程中常见的数据类型错误,并提供相应的解决方法。 类型不匹配 类型不匹配是GO编程中最常见的类型错误之一。它通常发生在将一个类型的值赋给另一个类型时。 例如,下...
    99+
    2023-09-20
    关键字 数据类型 编程算法
  • Apache 服务器中数据类型的常见错误和解决方法
    Apache服务器是一个广泛使用的服务器软件,许多网站都依赖于它来提供服务。在开发和部署网站时,经常需要与不同类型的数据打交道。在这个过程中,数据类型的错误可能会导致很多问题,这篇文章将介绍 Apache 服务器中数据类型的常见错误和解决方...
    99+
    2023-07-04
    数据类型 spring apache
  • PHP7中的标量类型声明:如何预防常见的类型错误?
    PHP7中的标量类型声明:如何预防常见的类型错误?在PHP7中,引入了标量类型声明,它是一种新的特性,可以在函数和方法参数以及返回值的位置上指定预期的数据类型。这对于避免常见的类型错误非常有帮助。本文将通过具体的代码示例来介绍如何利用标量类...
    99+
    2023-10-22
    PHP 标量类型声明 预防类型错误
  • JavaScript开发中常见错误解决是怎样的
    JavaScript开发中常见错误解决是怎样的,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。身为一名前端打工人,当然是经验越多,在排查错误...
    99+
    2022-10-19
  • thinkphp请求类型错误如何解决
    今天小编给大家分享一下thinkphp请求类型错误如何解决的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。首先,我们来了解一下...
    99+
    2023-07-05
  • PHP7中的Type Hinting特性:如何防止常见的类型错误?
    PHP7中的Type Hinting特性:如何防止常见的类型错误?在编程语言中,类型错误是经常出现的错误之一。PHP7引入了Type Hinting特性,使得开发者能够在函数声明中指定参数的类型,以及函数的返回值类型。Type Hintin...
    99+
    2023-10-22
    PHP Type Hinting 错误防止
  • C++中常见的数据类型问题的解决方法
    C++中常见的数据类型问题的解决方法引言:在C++编程中,处理不同数据类型的问题是非常常见的。不同的数据类型具有不同的特征和用途,然而,在处理不同类型的数据时,我们经常会遇到一些问题。本文将介绍一些在处理C++中常见数据类型问题时的解决方法...
    99+
    2023-10-22
    数据类型 C++ 解决方法
  • java已定义类型错误如何解决
    要解决Java中已定义类型错误,可以尝试以下方法:1. 检查已导入的类:确保已正确导入需要使用的类。可以使用import语句导入类,...
    99+
    2023-08-29
    java
  • java类型转换异常如何解决
    Java类型转换异常通常是由于将一个数据类型转换为另一个不兼容的数据类型导致的。要解决这个问题,可以采取以下几种方式:1. 检查转换...
    99+
    2023-09-27
    java
  • PHP中的数据类型与日志同步:如何避免常见错误?
    PHP是一种强大的编程语言,它支持多种数据类型,包括整数、浮点数、字符串、布尔值、数组、对象等。在处理数据时,我们经常需要将数据记录到日志中,以便于排查问题和进行调试。但是,在将数据记录到日志中时,我们也经常会遇到一些常见的错误。本文将介绍...
    99+
    2023-06-08
    日志 数据类型 同步
  • C#中常见的数据类型转换问题及解决方案
    C#中常见的数据类型转换问题及解决方案在C#中,数据类型转换是一个常见的问题。由于C#是一种强类型语言,要求变量在进行计算或赋值时类型必须匹配。因此,当我们需要将一个数据类型转换为另一个数据类型时,可能会遇到各种问题。本文将介绍常见的数据类...
    99+
    2023-10-22
    数据类型转换解决方案
  • Python开发中常见的数据类型问题及解决策略
    Python开发中常见的数据类型问题及解决策略概述:在Python开发过程中,处理数据是一个非常常见的任务。然而,由于数据的多样性和复杂性,很容易出现一些数据类型相关的问题。本文将介绍一些常见的数据类型问题,并提供相应的解决策略和代码示例。...
    99+
    2023-10-22
    策略 数据类型 问题
  • C++中常见的数据类型转换问题及解决方法
    C++ 中常见的数据类型转换问题及解决方法引言:在 C++ 编程中,经常会遇到不同数据类型之间的转换问题。正确地进行数据类型转换是保证程序正确性和性能的关键之一。本文将介绍一些常见的数据类型转换问题,并提供相应的解决方法和具体的代码示例。一...
    99+
    2023-10-22
    解决方法 数据类型转换 C++问题
  • Python和JavaScript编程中常见的日志错误及其解决方案
    Python和JavaScript作为现今最常用的编程语言之一,具有广泛的应用场景。在开发过程中,我们经常会遇到各种错误。其中,日志错误是最常见的问题之一。在本文中,我们将讨论。 一、Python编程中常见的日志错误 日志格式化错误 在...
    99+
    2023-08-16
    javascript 日志 编程算法
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作