理解js的精度问题

news2024/9/20 9:07:04

参考博客:js精度丢失问题-看这篇文章就够了(通俗易懂)、探寻 JavaScript 精度问题以及解决方案、JavaScript 浮点数陷阱及解法

1 为什么

JavaScript 中所有数字包括整数和小数都只有一种类型 即 Number类型,它的实现遵循 IEEE 754 标准

在这里插入图片描述

  • 符号位S:0代表正数,1代表负数
  • 指数位E:存储指数,用来表示次方数
  • 尾数位M:存储尾数,超出的部分自动进1舍0

计算方法:
在这里插入图片描述

因为存储时有位数限制(64位),并且某些十进制的浮点数在转换为二进制数时会出现无限循环,会造成二进制的舍入操作(0舍1入),当再转换为十进制时就造成了计算误差。

了解了存储方法之后,再以0.1来解释一下浮点误差的问题。

将十进制小数 0.1 转为二进制:

0.1 * 2 = 0.2
0.2 * 2 = 0.4 // 循环
0.4 * 2 = 0.8
0.8 * 2 = 1.6
0.6 * 2 = 1.2
0.2 * 2 = 0.4 // 循环
0.4 * 2 = 0.8
0.8 * 2 = 1.6
0.6 * 2 = 1.2
...

可以发现有限十进制小数 0.1 被转化成了无限二进制小数 0.00011001100...(0011循环),表示为科学记数法为1.100110011001100...x2^-4,所以 E=-4+1023=1019M=100110011...。由于计算机存储的长度又是有限的,所以在一定长度后会进行舍入操作,如图所示,尾数部分存在进位,精度就丢失了。

在这里插入图片描述

再从计算机中取出来的二进制数,是被进位处理过的,转化成十进制后为 0.100000000000000005551115123126,因此就出现了浮点误差。

计算机存储一个27.5的数字

  • 首先把这个数字转换为二进制 11011.1
  • 再把二进制转换为科学记数法 1.10111∗2^4
  • 又因js存储数字用的是双精度浮点数【最多存储64位】 即 符号位【1】+指数位【4+1023(固定偏移量)=> 10000000011】+小数部分【10111(52位不够用0补齐)】
  • 0100 0000 0011 1011 1000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000

最大安全数的由来:

  • 2位 ===> 2^2=4种组合 ===> 表示的最大十进制整数2^2-1=3

  • 精度位53位 ===> 2^53种组合 ===> 表示的最大十进制整数2^53-1=9007199254740991

能被转化为有限二进制小数的十进制小数的最后一位必然以 5 结尾(因为只有 0.5 * 2 才能变为整数)。所以十进制中一位小数 0.1 ~ 0.9 当中除了 0.5 之外的值在转化成二进制的过程中都丢失了精度。

2 业务场景

场景一:大数危机

比如有个订单号后端定义的是 long 类型,但是当这个订单号转换成 JavaScript 的 Number 类型时候精度会丢失。

preview:

img

response:

img

preview中的值是错误的,response中的值是正确的,postman中请求的值跟response是一致的,那说明问题就出现在浏览器中。

查阅资料知道,在preview中,控制台会把发送过来的json数据自动转换成javascript的对象格式,而js的Number类型并不能完全表示Long型的数字,当它超过最大安全数(Math.pow(2, 53) - 1,即 9007199254740991)时,就可能会发生精度丢失的问题。

解决方法:

方案一:在返回数据之前就将数据转换为字符串。
方案二:在传递给 then/catch 前,结合开源库json-bigint,使用transformResponse修改响应数据。

import JSONBig from 'json-bigint';

const res = await axios({
  url: requestUrl,
  params: queryStringParameters,
  data,
  method,
  transformResponse: [
    function (resData) {
      try {
        return JSONBig.parse(resData);
      } catch (e) {
        return JSON.parse(resData);
      }
    },
  ],
});

另外一个情况,如果我门需要使用大于最大安全数的整数,则可以考虑使用BigInt数据类型,它可以表示大于 2^53 - 1 的整数。

9007199254740991+2 // 9007199254740992

9007199254740991n+2n // 9007199254740993n

场景二:浮点数的加减乘除

比如涉及费用计算的时候,可能会存在小数相乘的情况。如下图,1222.1*100000应该等于的是122210000,但js乘出来的结果却是122209999.99999999,这也是因为精度丢失导致的。

在这里插入图片描述
在这里插入图片描述

解决方法:

方案一:扩大缩小法,将小数转换成字符串,记录小数点后面的位数的长度,再转换成整数相乘,最后除以扩大倍数。

function twoNumberMulti(multiplicand, multiplier) {
  let m = 0;
  const multiplicandStr = String(multiplicand);
  const multiplierStr = String(multiplier);
  if (multiplierStr.includes('.')) {
    m += multiplierStr?.split('.')[1]?.length || 0;
  }
  if (multiplicandStr.includes('.')) {
    m += multiplicandStr?.split('.')[1]?.length || 0;
  }
  return (Number(multiplicandStr.replace('.', '')) * Number(multiplierStr.replace('.', ''))) / 10 ** m;
}

console.log(twoNumberMulti(1222.1,100000)) // 122210000

方案二:开源库number-precision,将小数转为整数后再作处理,支持浮点数的加减乘除、四舍五入等运算。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/391898.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

MySQL运维篇之Mycat分片规则

3.5.3、Mycat分片规则 3.5.3.1、范围分片 根据指定的字段及其配置的范围与数据节点的对应情况,来决定该数据属于哪一个分片。 示例: 可以通过修改autopartition-long.txt自定义分片范围。 注意: 范围分片针对于数字类型的字段,…

Kubernetes Pod 水平自动伸缩(HPA)

Pod 自动扩缩容 之前提到过通过手工执行kubectl scale命令和在Dashboard上操作可以实现Pod的扩缩容,但是这样毕竟需要每次去手工操作一次,而且指不定什么时候业务请求量就很大了,所以如果不能做到自动化的去扩缩容的话,这也是一个…

IO文件操作

认识文件 狭义的文件 存储在硬盘上的数据,以“文件"为单位,进行组织 常见的就是普通的文件 (文本文件,图片, office系列,视频,音频可执行程序…)文件夹也叫做"目录" 也是一种特殊的文件。 广义的文件 操作系统,是要负责管理软硬件资源,操作系统(…

更高效的跨端开发选择:基于小程序容器的Flutter应用开发

为什么说Flutter是一个强大的跨端框架? Flutter是一个基于Dart编程语言的移动应用程序开发框架,由Google开发。它的强大之处在于它可以快速构建高性能、美观、灵活的跨平台应用程序,适用于Android、iOS、Web、Windows、macOS和Linux等多个平…

Git图解-常用命令操作

目录 一、前言 二、初始化仓库 三、添加文件 四、Git 流程全景图 五、Git工作流程 六、工作区和暂存区 七、查看文件状态 八、查看提交日志 九、查看差异 十、版本回退 十一、管理修改 十二、修改撤销 十三、删除文件 十四、分支管理 十五、项目分支操作 十六、…

Centos7使用OVS桥的方式创建KVM虚拟机

一、OVS使用 1、OVS编译安装 下载ovs2.17版本源码 http://www.openvswitch.org//download/ ./boot.sh ./configure make && make install2、启动OVS服务 (1)创建文件/etc/systemd/system/openvswitch.service [rootlocalhost qemu]# syste…

Spring Cloud Alibaba全家桶(五)——微服务组件Nacos配置中心

前言 本文小新为大家带来 微服务组件Nacos配置中心 相关知识,具体内容包括Nacos Config快速开始指引,搭建nacos-config服务,Config相关配置,配置的优先级,RefreshScope注解等进行详尽介绍~ 不积跬步,无以至…

【面试题】如何避免使用过多的 if else?

大厂面试题分享 面试题库前后端面试题库 (面试必备) 推荐:★★★★★地址:前端面试题库一、引言相信大家听说过回调地狱——回调函数层层嵌套,极大降低代码可读性。其实,if-else层层嵌套,如下图…

.NET 8 预览版 1 发布!

.NET 8 是一个长期支持(LTS) 版本。这篇文章涵盖了推动增强功能优先级排序和选择开发的主要主题和目标。.NET 8 预览版和发布候选版本将每月交付一次。像往常一样,最终版本将在 11 月的某个时候在 .NET Conf 上发布。 .NET 版本包括产品、库、运行时和工具&#xf…

JavaSE学习笔记总结day19

今日内容 二、线程安全的集合 三、死锁 四、线程通信 五、生产者消费者 六、线程池 零、 复习昨日 创建线程的几种方式 1) 继承 2) 实现Runnable 3) callable接口 Future接口 4) 线程池 启动线程的方法 start() 线程的几种状态 什么是线程不安全 setName getName Thread.curr…

基于intel soc+fpga智能驾驶舱和高级驾驶辅助系统软件设计(三)

虚拟化操作系统介绍 车载平台有逐渐融合的趋势,车载 SoC 的计算性能和应用快速增长,面临着多种应用在 多个显示子系统融合在一起的问题,这就要求平台运行多个操作系统。虚拟化(Virtualization) 技术飞速发展&#xff0…

软件测试培训三个月,找到工作了11K,面试总结分享给大家

功能方面:问的最多的就是测试流程,测试计划包含哪些内容,公司人员配置,有bug开发认为不是 bug怎么处理,怎样才算是好的用例,测试用例设计方法(等价类,边界值等概念方法)&…

ETL的模式以及优缺点

首先,ETL有四种主要实现模式:触发器模式、增量字段、全量同步、日志比对。其次,四种模式的优缺点触发器模式优点:数据抽取的性能高,ETL 加载规则简单,速度快,不需要修改业务系统表结构&#xff…

科目二练习与考试点位总结

一,开车前检查1.调整桌椅。2.调整左右后视镜。3.系安全带。二、倒车入库右边倒车直行至左肩与左虚线重合停车,倒车,左视镜下沿与左虚线重合或10cm左右,方向盘右打满。看右视镜第二个虚线一半回一圈。看右视镜右库角消失右打满。观…

Qt音视频开发20-vlc内核动态保存录像文件(不需要重新编译源码)

一、前言 在vlc默认提供的保存文件方式中,通过打开的时候传入指定的参数来保存文件,直到关闭播放生成文件,这种方式简单暴力,但是不适用大部分的场景,大部分时候需要的是提供开始录制和停止录制的功能,也就…

【springmvc】Rest ful风格

RESTful 1、RESTful简介 REST:Representational State Transfer,表现层资源状态转移。 a>资源 资源是一种看待服务器的方式,即,将服务器看作是由很多离散的资源组成。每个资源是服务器上一个可命名的抽象概念。因为资源是一…

华为OD机试题,用 Java 解【获取最大软件版本号】问题

华为Od必看系列 华为OD机试 全流程解析+经验分享,题型分享,防作弊指南)华为od机试,独家整理 已参加机试人员的实战技巧华为od 2023 | 什么是华为od,od 薪资待遇,od机试题清单华为OD机试真题大全,用 Python 解华为机试题 | 机试宝典使用说明 参加华为od机试,一定要注意不…

如何用MD5和SHA等构造密码方案中的哈希函数

文章目录常见符号如何实现 H:{0,1}∗→Zp∗H : \{0, 1\}^* \to \mathbb{Z}^*_pH:{0,1}∗→Zp∗​如何实现 H:Zp∗→{0,1}λH: \mathbb{Z}^*_p \to \{0, 1\}^\lambdaH:Zp∗​→{0,1}λ如何实现 H:M→ZN∗H: \mathcal{M} \to \mathbb{Z}^*_NH:M→ZN∗​如何实现 H:{0,1}∗→GH: \…

ElasticSearch - ElasticSearch基本概念及集群内部原理

文章目录1. ElasticSearch的应用场景01. Elasticsearch 是什么?02. 为何使用 Elasticsearch?03. Elasticsearch 的用途是什么?04. Elasticsearch 的工作原理是什么?05. Elasticsearch 索引是什么?06. Logstash 的用途是…

SAP UI5 Upload/Download file through NetWeaver Gateway

1、创建 SEGW对象 2、创建Entity Type 要把Media 标识打上 3、 激活对象然后到DPC Class的扩展对象里面重定义 /IWBEP/IF_MGW_APPL_SRV_RUNTIME~GET_STREAM /IWBEP/IF_MGW_APPL_SRV_RUNTIME~CREATE_STREAM /IWBEP/IF_MGW_APPL_SRV_RUNTIME~UPDATE_STREAM METHOD /iwbep/if_m…