JavaScript 中 0.1 + 0.2 != 0.3:浮点数运算的陷阱

引言

在日常的 JavaScript 开发中,我们经常会面对一些看似简单的数学运算。然而,当我们执行 0.1 + 0.2 这样的操作时,很多人可能会感到困惑,因为预期的结果应该是 0.3,但实际上却是一个略微不同的值。这个现象是由于 JavaScript 中浮点数运算的特性导致的,本文将深入探讨这个问题的背后原因以及如何在开发中避免相关的陷阱。

为什么会发生这种情况?

在计算机中,浮点数是用二进制表示的,而不是十进制。由于这一事实,一些十进制小数可能无法精确地用二进制表示,从而导致在浮点数运算中产生舍入误差。JavaScript 使用的是 IEEE 754 标准来表示浮点数,这一标准采用二进制表示法,因此在某些情况下,十进制小数无法完全精确映射到二进制表示。

在具体到 0.1 + 0.2 的例子中,这两个数字在二进制中的表示并不是精确的。虽然它们在十进制下是简单的小数,但在二进制中,它们的精确表示是一个无限循环小数。由于计算机的存储和运算能力的限制,这样的无限循环小数无法被精确表示,因此就会引发舍入误差。

console.log(0.1 + 0.2); // 输出 0.30000000000000004

浮点数运算的挑战

1. 精度丢失

在 JavaScript 中,由于浮点数运算的不可避免的舍入误差,可能会导致精度丢失。这意味着在比较两个浮点数是否相等时,应该使用一些技巧,而不是直接使用相等运算符。

console.log(0.1 + 0.2 === 0.3); // 输出 false
console.log(Math.abs(0.1 + 0.2 - 0.3) < Number.EPSILON); // 输出 true

2. 运算顺序的影响

JavaScript 的浮点数运算还受到运算顺序的影响。由于浮点数的表示范围和精度有限,当进行多个浮点数的运算时,不同的运算顺序可能导致不同的结果。

console.log(0.1 + 0.2 + 0.3); // 输出 0.6000000000000001
console.log(0.3 + 0.2 + 0.1); // 输出 0.6

3. 解决方案:使用整数进行运算

为了避免浮点数运算的陷阱,一种常见的做法是将浮点数转换为整数进行运算,然后再将结果转换回浮点数。这可以通过乘以一个足够大的倍数来实现。

let result = (0.1 * 10 + 0.2 * 10) / 10;
console.log(result); // 输出 0.3

如何在开发中避免问题?

在实际的开发中,我们可以采取一些策略来最小化浮点数运算带来的问题。

1. 使用整数进行运算

如前所述,将浮点数转换为整数进行运算是一种可行的解决方案。通过乘以一个足够大的倍数,我们可以避免舍入误差。

2. 使用专门的库

一些专门处理精确数学运算的库,如 Decimal.js 和 big.js,提供了更精确的十进制运算,可以在避免浮点数问题的同时保持较高的性能。

3. 使用 Number.EPSILON 进行比较

在比较浮点数是否相等时,应该使用一个很小的常量,例如 Number.EPSILON,而不是直接使用相等运算符。

console.log(Math.abs(0.1 + 0.2 - 0.3) < Number.EPSILON); // 输出 true

4. 注意运算顺序

在进行多个浮点数的运算时,应该注意运算顺序可能带来的不同结果。在关键的业务逻辑中,可以考虑重新排列运算的顺序,以最小化舍入误差的影响。

5.自定义向上向下取整

只要跟钱有关,那这个问题就必须得重视了,js中并没有针对精度保留向上向下的方法,当时我们可以利用原生的 Math.powMath.floor 二次封装,根据实际场景决定向上保留精度还是向下保留精度;

/*** 向下取整 例如:3.33333333 取3位,返回 3.333* num 原始值* precision 保留精度*/
Math.floorPow = function(num, precision){// 根据保留精度放大 小数位let magnify =  Math.pow(10, precision);// 返回小于等于给定数字的 最大整数return Math.floor(num * magnify)/magnify;
}/*** 向上取整 例如:3.33333333 取3位,返回 3.334* num 原始值* precision 保留精度*/
Math.ceilPow = function(num, precision){// 根据保留精度放大 小数位let magnify =  Math.pow(10, precision);// 返回小于等于给定数字的 最大整数return Math.ceil(num * magnify)/magnify;
}

结语

JavaScript 中 0.1 + 0.2 不等于 0.3 的现象并非 bug,而是由于浮点数运算的本质导致的。了解浮点数运算的特性,采用适当的解决方案,可以帮助我们避免在开发中因为这类问题而浪费时间。通过合理的数学运算和注意运算顺序,我们可以更好地利用 JavaScript 的数值计算功能,确保我们的应用在处理数学运算时保持准确性和可靠性。

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

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

相关文章

5、C语言:结构

结构 结构的基本知识结构与函数传递结构 结构数组、指向结构的指针自引用结构&#xff08;二叉树&#xff09;表查找类型定义&#xff08;typedef&#xff09;联合位字段 结构也是一种数据类型。类似于int、char、double、float等。 结构是一个或多个变量的集合&#xff0c;这些…

c++学习笔记-STL案例-机房预约系统1-准备工作

前言 准备工作包括&#xff1a;需求分析、项目创建、主菜单实现、退出功能实现 目录 1 机房预约系统需求 1.1 简单介绍 1.2 身份介绍 1.3 机房介绍 1.4 申请介绍 1.5 系统具体要求 1.6 预约系统-主界面思维导图 2 创建项目 2.1 创建项目 2.2 添加文件 ​编辑 3 创建…

页面跳转后,默认选中tree节点并高亮显示

1.场景 操作步骤&#xff1a; 1.点击数据连接数&#xff0c;打开弹窗 2.点击连接状态跳转到数据连接模块 3.默认选中tree的数据源id节点 2.代码 参数解释&#xff1a; 3.实现逻辑 首先将id通过组件传参的方式传过去&#xff0c;数据连接接收后&#xff0c;在tree里设置…

ubuntu 挂载新硬盘

1、检测新硬盘 新增加硬盘&#xff0c;检测硬盘识别情况。 命令检查&#xff1a;sudo fdisk -l 3、格式化磁盘 格式化&#xff1a;sudo mkfs.ext4 /dev/sdb 其中&#xff0c;/dev/sdb是新分区的设备文件名&#xff0c;ext4是要使用的文件系统类型。 4、挂载新分区 sudo mk…

【银行测试】24年金融银行项目,10道高频测试面试题汇总...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 面试题1&#xff…

使用AUTOSAR来开发汽车基础软件的优点

1、高质量。以前我们采用手写代码的方式&#xff0c;是几个工程师在战斗。现在我们采用平台&#xff0c;BSW代码都是供应商提供的&#xff0c;我们相当于后面还有一个团队陪着我们在战斗。 2、低成本。大家都说采用AUTOSAR平台好贵&#xff0c;但是从长远来看是值得的&#xff…

计算机毕业设计----ssm开发的Java快递代拿系统

使用技术 采用 Spring SpringMVC MyBatisPlus&#xff0c;连接池采用 Druid&#xff0c;安全框架使用 Shiro&#xff0c;前端采用 Bootstrap layer 实现。 支付采用支付宝沙箱环境&#xff0c;支付APP下载链接&#xff0c;[点击这里](https://sandbox.alipaydev.com/user/…

SpringBoot中使用SpringEvent业务解耦神器实现监听发布事件同步异步执行任务

场景 SpringBoot中使用单例模式ScheduledExecutorService实现异步多线程任务(若依源码学习)&#xff1a; SpringBoot中使用单例模式ScheduledExecutorService实现异步多线程任务(若依源码学习)-CSDN博客 设计模式-观察者模式在Java中的使用示例-环境监测系统&#xff1a; 设…

GPT实战系列-简单聊聊LangChain

GPT实战系列-简单聊聊LangChain LLM大模型相关文章&#xff1a; GPT实战系列-ChatGLM3本地部署CUDA111080Ti显卡24G实战方案 GPT实战系列-Baichuan2本地化部署实战方案 GPT实战系列-大话LLM大模型训练 GPT实战系列-探究GPT等大模型的文本生成 GPT实战系列-Baichuan2等大模…

SpringBoot中使用LocalDateTime踩坑记录

文章目录 前言一、为什么推荐使用java.time包的LocalDateTime而不是java.util的Date&#xff1f;二、使用LocalDateTime和LocalDate时遇到了哪些坑&#xff1f;2.1 Redis序列化报错2.1.1 问题现象2.1.2 问题分析2.1.3 解决方案 2.2 LocalDateTime和LocalDate类型的属性返回给前…

分享一个实现侧滑菜单的Flutter页面所遇到的问题与解决思路

最近做了一个需要实现侧滑菜单相关的Flutter新页面&#xff0c;页面布局结构稍微比较复杂。因此&#xff0c;做完之后就对研发的过程做出一些整理。 以下主要整理跟侧滑菜单相关的内容。直奔主题&#xff0c;首先&#xff0c;要实现侧滑菜单&#xff0c;有以下几个方案。而本次…

类型特质和静态断言

static_assert( constant-expression, string-literal );static_assert( constant-expression ); // C17 (Visual Studio 2017 and later) constant-expression 可以转换为布尔值的整型常量表达式。 如果计算出的表达式为零 (false)&#xff0c;则显示 string-literal 参数&…

PyTorch|view(),改变张量维度

在构建自己的网络时&#xff0c;了解数据经过每个层后的形状变化是必须的&#xff0c;否则&#xff0c;网络大概率会出现问题。PyToch张量有一个方法&#xff0c;叫做view(),使用这个方法&#xff0c;我们可以很容易的对张量的形状进行改变&#xff0c;从而符合网络的输入要求。…

React 18中新钩子 useDeferredValue 使用

React是一个流行的用于构建用户界面的JavaScript库,它不断发展以为开发人员提供优化性能的工具。 React 18中引入的此类工具之一是useDeferredValue钩子,它旨在通过优先渲染更新来提高应用程序的性能。 useDeferredValue钩子是什么? useDeferredValue钩子是React性能优化工…

SAP PP配置学习(五)

查找 四、 其它 设置 MM 过帐号码范围 定义凭证号码范围 OB52 打开期间 MMPV 开帐 &#xff08;下篇见&#xff09;

K-【学习Diffusers 四】 读取模型参数 bin格式、safetensors格式

该操作多用于推理 safetensors格式的参数读取方法 1 拿到pipeline中的unet的办法 unet pipeline.pipe.unet 2 safetensors格式文件的参数读取方法 state_dict safetensors.torch.load_file(args.model_id, device"cpu") unet.load_state_dict(state_dict) # 读入…

随心玩玩(十二)通义千问——LLM大模型微调

写在前面&#xff1a;使劲的摸鱼&#xff0c;摸到的鱼才是自己的~ 文章目录 简介环境配置模型加载jupyter远程配置快速使用微调示例部署方案总结附录&#xff1a; ReAct Prompting 示例准备工作一&#xff1a;样例问题、样例工具准备工作二&#xff1a;ReAct 模版步骤一&#x…

MySQL:DML数据操作语言(添加,删除,修改),DDL数据查询语言(条件查询,分组查询,排序查询,分页查询)

目录 1.DML&#xff08;数据操作语言&#xff09;1.添加数据2.修改数据3.删除数据 2.DQL(数据查询语言)1.DQL-语法2.基本查询3.条件查询(WHERE)1.语法&#xff1a;2.条件&#xff1a;3.案例: 4.聚合函数1.介绍2.常见聚合函数3.语法4.案例 5.分组查询&#xff08;GROUP BY&#…

物联网通讯协议NB-lot和LoRa差异分析

像把大象装冰箱一样&#xff0c;物联网&#xff0c;万物互联也是要分步骤的。 一、感知层(信息获取层)&#xff0c;即利用各种传感器等设备随时随地获取物体的信息; 二、网络层(信息传输层)&#xff0c;通过各种电信网络与互联网的融合&#xff0c;将物体的信息实时准确地传递…

力扣LCR 166. 珠宝的最高价值(java 动态规划)

Problem: LCR 166. 珠宝的最高价值 文章目录 解题思路思路解题方法复杂度Code 解题思路 思路 改题目与本站64题实质上是一样的&#xff0c;该题目在64题的基础上将求取最小路径和改成了求取最大路径和。具体实现思路如下&#xff1a; 1.定义一个int类型的二维数组dp大小为给定…