0.1 + 0.2 不等于 0.3 ?这是为什么?一篇讲清楚!!!

0.1 + 0.2 不等于 0.3 ?这是为什么?一篇讲清楚!!!

分类 编程技术

在很多编程语言中,我们都会发现一个奇怪的现象,就是计算 0.1 + 0.2,它得到的结果并不是 0.3,比如 C、C++、JavaScript 、Python、Java、Ruby 等,都会有这个问题。

为此,有人还做出了一个 Floating Point Math 网站,在这个网站上我们可以找到哪些编程语言在计算 0.1 + 0.2 的结果并不是 0.3,而是 0.30000000000000004。

我们可以用 JavaScript 来做演示,计算 0.1 + 0.2,它得到的结果并不是0.3,而是 0.30000000000000004。

当然如果你把它作为条件判断语句,返回的也是 false:

还有其他的例子:

6 * 0.1 = 0.6 但计算机显示为 0.6000000000000001​
0.11 + 0.12 = 0.23 但计算机显示为 0.22999999999999998​
0.1 + 0.7 = 0.8 但计算机显示为 0.7999999999999999​
0.3+0.6 = 0.9 但计算机显示为0.8999999999999999

而以下几个计算式却能得到我们想要的结果:

这是为什么呢?

简单来说,计算机使用基于二进制的浮点数,而我们人类使用基于十进制的浮点数。

在二进制中,,浮点数通常使用 IEEE 754 标准进行表示,无法准确表示的小数有 0.1、0.2 或 0.3 这样的数字,因为它使用的是二进制浮点格式。

IEEE 754 标准可以参见:https://zh.wikipedia.org/wiki/IEEE_754

背后原理

在十进制系统中,如果一个分数使用基数(10)的质因数来表示,那么它可以被精确地表示。

10 的质因数是 2 和 5。

因此,1/2、1/4、1/5 (0.2)、1/8 和 1/10 (0.1) 可以被精确地表示,因为分母使用了 10 的质因数。

而 1/3、1/6 和 1/7 是无限循环的小数,因为分母使用了 3 或 7 的质因数。

在二进制(计算机使用的系统)中,如果一个分数使用基数(2)的质因数来表示,那么它可以被精确地表示。

2 是 2 的唯一质因数。

因此,1/2、1/4 和 1/8 都可以被精确地表示,因为分母使用了 2 的质因数。

而 1/5 (0.2) 或 1/10 (0.1) 是无限循环的小数,因为分母使用了 5 或 10 的质因数。

所以当我们尝试表示像 0.1 这样的十进制小数时,计算机会使用一个近似值。这个近似值是通过将无限循环的二进制小数转换为有限位数的浮点数表示来实现的。

因此,当我们在计算机中进行浮点数运算时,结果可能会有微小的误差。

例如,0.1 在二进制中的近似表示可能是 0.000110011001100...,但在计算机的浮点数表示中,它可能被截断或舍入为 0.00011001100110,这就导致了 0.1 + 0.2 在计算机中可能不等于 0.3,而是略微有所偏差。

0.1 是十分之一(1/10),要得到 0.1 的二进制表示(即二进制形式),我们需要使用二进制长除法,即将二进制数1除以二进制的 1010(即1/1010),如下所示:

因此,0.1 在二进制中的表示为 0.0001100110011001100110011...(无限循环)。

这个无限循环的模式 0011 会一直重复下去,因为二进制系统只能通过这种方式来近似表示十进制中的 0.1。

在实际的计算机系统中,这个无限循环的小数会被截断为有限位数,以便存储和计算。这就导致了在计算机中进行二进制浮点数运算时,可能会出现精度损失,从而使得 0.1 和 0.2 的和不完全等于0.3。

十进制小数转二进制

还有一种更容易理解的方法(采用 *2 取整法),例如我们要把十进制数的小数 0.875 转换为二进制数,只需将十进制数的小数部分乘以 2,然后提取整数部分,直到小数部分变为 0。

将上面提取的整数部分排列的结果 111 变成以二进制表示的 .875。

二进制数 1101.111 整数部分为 1101 ,小数部分为 111,就是十进制数 13.875 转换为二进制的结果。

按以上的方法我们将十进制小数 0.1 转化为二进制就是:

0.1 = 0.0001100110011001100110011001100110011001100110011001101...

十进制小数 0.2 转化为二进制就是:

0.2 = 0.001100110011001100110011001100110011001100110011001101...


解决办法

1、小数先转整数

可以先把小数转换成整数,再相加之后转回小数,如下实例:

(0.1*10 + 0.2*10)/10

2、使用 toFixed() 方法

toFixed() 方法可以将一个数字转换为指定小数位数的字符串表示形式。

下面是一个使用 toFixed() 方法解决浮点数精度问题的例子:

let sum = 0.1 + 0.2;
console.log(sum.toFixed(2)); // 输出: 0.30

需要注意的是,toFixed()方法虽然在显示上解决了问题,但它并没有改变数字的实际值,它只是改变了数字的表示形式。

如果你需要进行精确的数学运算,可能需要使用其他方法,比如引入一个精度更高的数值类型或者使用第三方的数学库来处理浮点数运算。

3、使用 decimal.js 库

在 JavaScript 中处理浮点数的精度问题时,使用 decimal.js 库是一个更为精确和可靠的解决方案。

decimal.js 是一个任意精度的十进制数学库,它能够避免原生 JavaScript 中浮点数运算的不精确性。

Github 地址:GitHub - MikeMcl/decimal.js: An arbitrary-precision Decimal type for JavaScript

首先,你需要在你的项目中引入 decimal.js 库。

使用 npm 安装:

npm install decimal.js

在 HTML 中引入:

<script src="https://cdnjs.cloudflare.com/ajax/libs/decimal.js/10.2.0/decimal.min.js"></script>

接下来,你可以使用 decimal.js 来处理浮点数的运算,下面是一个例子:

实例

// 引入Decimal构造函数
const Decimal = decimal. Decimal;

// 创建两个Decimal对象
let a = new Decimal('0.1');
let b = new Decimal('0.2');

// 进行加法运算
let sum = a.plus(b);

// 输出结果
console.log(sum.toString()); // 输出: 0.3

使用 decimal.js 库得到的结果是准确的 0.3,而不是原生 JavaScript 中的近似值。

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

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

相关文章

高效保护,无粉乳胶手套助您安心工作

在快节奏的现代生活中&#xff0c;我们每天都在与各种细菌、污染物和化学品打交道&#xff0c;因此保护我们的身体健康变得愈发重要。特别是在工作环境中&#xff0c;手部是最容易受到伤害和污染的部位之一。为了提供最佳的保护&#xff0c;优斯特推出了一款高品质的无粉乳胶手…

C语言---顺序表(二)

文章目录 前言1.准备工作2.代码的实现2.1.顺序表的创建、销毁和打印2.2.顺序表的扩容、头插\删、尾插\删2.2.1.扩容2.2.2.尾插2.2.3.头插2.2.3.尾删2.2.4.头删 2.3.指定位置之前插入/删除数据/查找数据2.3.1.指定位置之前插入数据2.3.2.指定位置之前删除数据2.3.3.查找特定数据…

Freecad参数化三维建模的趋势——水利水电设计

最近以chatgpt3.5彻底放开和Kimi小程序如此方便使用而火爆。 三维参数化模型是一个趋势&#xff0c;特别对于这些常规的建筑物设计&#xff0c;基本极少各种曲线曲面&#xff0c;所以特别适合做参数化。 而水利水电工程上应用的设备和产品&#xff0c;也可以建立参数化库&…

微信小程序 uniapp+vue.js医疗在线问诊挂号系统4oy17

预约挂号系统的逐渐发展&#xff0c;进一步方便了广大用户&#xff0c;使其可以更方便、快捷地预约挂号&#xff0c;并且也有效地防止号贩子“倒号”&#xff0c;使用户预约挂号更公平&#xff0c;然而现有预约挂号系统或多或少有所欠缺 小程序前端框架&#xff1a;uniapp 小程…

LeetCode 2529. 正整数和负整数的最大计数——每日一题

上一篇博客&#xff1a;LeetCode 993. 二叉树的堂兄弟节点——每日一题 写在前面&#xff1a;大家好&#xff01;我是晴空๓。如果博客中有不足或者的错误的地方欢迎在评论区或者私信我指正&#xff0c;感谢大家的不吝赐教。我的唯一博客更新地址是&#xff1a;https://ac-fun.…

「合肥*讯飞」4月19日PolarDB开源数据库沙龙,报名中!

庐州聚智&#xff0c;数字经济启航智慧海 江淮引才&#xff0c;科技浪潮激荡智慧潮 4月19日周五&#xff0c;PolarDB开源社区联合科大讯飞共同举办开源数据库技术沙龙&#xff0c;本次沙龙我们邀请了众多数据库领域的专家&#xff0c;与广大数据库开发者和爱好者们进行技术交…

三十一 超级数据查看器 教程 列表界面的特殊功能

三十一 超级数据查看器 教程 列表界面的特殊功能 点击 打开该讲的视频 点击访问app下载页面 豌豆荚 下载地址 大家好&#xff0c;这一课我们讲一下超级数据查看器的特殊功能&#xff0c;特殊功能能在列表界面空白处点击后&#xff0c;执行一些特殊的功能 首先&#xff0c;我们…

可视化展示点云数据——PCL

pcd文件的可视化 #include<pcl/io/pcd_io.h> #include<pcl/io/ply_io.h> #include<pcl/visualization/cloud_viewer.h>void viewerOneOff(pcl::visualization::PCLVisualizer& viewer) {viewer.setBackgroundColor(0, 0, 0); //设置背景颜色为黑色 }boo…

C#Socket通信实现多人联机和群发消息

1.服务器代码&#xff08;这个服务器每次接受消息后就会遍历连接的客户端&#xff0c;将消息发给其他所有的客户端&#xff09; using System; using System.Collections.Generic; using System.Net; using System.Net.Sockets; using System.Text; using System.Threading;pu…

【P2P】

文章目录 P2P应用纯P2P架构文件分发&#xff1a;C/S vs P2P文件分发时间&#xff1a;C/S模式文件分发时间&#xff1a;P2P模式 P2P文件分发&#xff1a;BitTorrentP2P文件分发&#xff1a;BitTorrentBitTorrent&#xff1a;请求&#xff0c;发送文件块BitTorrent&#xff1a;ti…

Java常用数据结构与集合

数据结构 数组&#xff1a; 内存地址连续检索效率高(可以通过下标访问成员)增删操作效率低(保证数据越界的问题,需动态扩容)长度固定&#xff0c;扩容的需要新的数组复制或者Arrays类的copyOf方法 链表 内存地址不连续查询快删除慢&#xff0c;因为需要移动指针又分双向链表…

基于Springboot的餐厅点餐系统

基于SpringbootVue的餐厅点餐系统的设计与实现 开发语言&#xff1a;Java数据库&#xff1a;MySQL技术&#xff1a;SpringbootMybatis工具&#xff1a;IDEA、Maven、Navicat 系统展示 首页展示 菜品详情页 菜品信息 个人中心 后台管理 菜品信息管理 用户管理 菜…