0.1+0.2为什么不等于0.3

13-为什么在JavaScript中0.1 + 0.2不等于0.3? 理解这一点,并采用适当的方法来处理浮点数计算,可以帮助我们避免相关的精度问题。首先,我们需要了解计算机是如何表示小数的。而在二进制中,并不是所有的十进制小数都能精确地表示。将这些十进制小数转换为二进制浮点数时,它们只能近似表示。但是,在二进制系统中,0.1表示为一个无限循环的小数,类似于在十进制中1/3表示为0.3333…对于需要高精度计算的场景,可以使用BigDecimal库进行处理,这些库能够精确处理十进制数。这并不是精确的0.3,而是一个非常接近0.3的数值,但在计算机的精度限制下,它们并不相等。 阅读详情

在这里插入图片描述

大家好,我是哪吒。

最近碰到一个问题,很有趣,我就不贴代码了,要不你们会以为我在无中生有。

在这里插入图片描述

我现在的心情很复杂,我想静静。

我只知道浮点数相加是丢失精度的,但是为什么会丢精度,我就不知道了。

一、0.1+0.2是如何执行的?

1、转成浮点数

浮点数在计算机内部是以二进制的形式存储的,而有些十进制的小数在二进制下无法精确表示,因此在进行浮点数运算时可能会存在精度误差。

浮点数分为单精度对应32位操作系统和双精度对应64位操作系统。目前的操作系统大多是64位操作系统,故这里只解释一下二进制如何转成双精度浮点数的二进制。

双精度浮点数用1位表示符号位,11位表示指数位,52位表示小数位,如下图所示:

在这里插入图片描述
符号位:正数为0,负数为1;
指数位:阶数+偏移量,阶数是:2^e-1^-1

e为阶码的位数。偏移量是把小数点移动到整数位只有1时移动的位数,正数表示向左移,负数表示向右移;

小数位:即二进制小数点后面的数。

接下来把0.1转成的二进制0.0001100110011001 …转成浮点数形式的二进制。

先要把小数点移动到整数位只有1,要向右移动4位,故偏移量为−4,通过指位数的计算公式2^11-1^-1-4=1019。

把1019转成二进制为1111111011,不够11位要补零,最终得出指位数为01111111011;

小数位为100110011001… ,因为小数位只能保留52位,第53位为1故进1。

转换结果如下图所示:

在这里插入图片描述
同理,再把 0.2 转成的二进制0.0011 0011 0011 0011… 转成浮点数形式的二进制,转换结果如下图所示:

在这里插入图片描述

2、浮点数相加

浮点数相加时,需要先比较指位数是否一致,如果一致则小数位直接相加,如果不一致,要先把指位数调成一致的,指位数小的向大的调整。

为了行文方便,把0.1转成的浮点数称为为0.1,把0.2转成的浮点数称为0.2。

0.1的指数位是1019 ,0.2的指数位是1020 。故要把0.1的指数位加1,即把0.1的小数点向左移动1位,另外浮点数的整数位固定为1,过程如下所示

浮点数相加时,需要先比较指位数是否一致,如果一致则小数位直接相加,如果不一致,要先把指位数调成一致的,指位数小的向大的调整。

为了行文方便,把0.1转成的浮点数称为为0.1,把0.2转成的浮点数称为0.2。

0.1的指数位是1019 ,0.2的指数位是1020 。故要把0.1的指数位加1,即把0.1的小数点向左移动1位,另外浮点数的整数位固定为1,过程如下所示

1.1001100110011001100110011001100110011001100110011010   原先
0.11001100110011001100110011001100110011001100110011010  移动后  
0.1100110011001100110011001100110011001100110011001101   将小数的第53位舍去,因为为0故不需进1

导致0.1的小数位变成如下所示:

在这里插入图片描述
会发现现在的小数位多出了一位,超出了52位,故要把小数位最后一位截掉,小数位最后一位是1,故要进1,如下所示:

10110011001100110011001100110011001100110011001100111
1011001100110011001100110011001100110011001100110100

截掉小数位的最后一位相当把小数点向左移了一位,故指数位要加1,此时的指数是0.2的指数1021 ,加1后变成1021 ,转成二进制为01111111101 ,那么相加后的浮点数如下所示:

在这里插入图片描述

3、浮点数转成十进制

在这里插入图片描述

因此,0.1+0.2 不等于 0.3 ,因为在 0.1+0.2 的计算过程中发生了两次精度丢失。

  • 第一次是在 0.1 和 0.2 转成双精度二进制浮点数时,由于二进制浮点数的小数位只能存储52位,导致小数点后第53位的数要进行为1则进1为0则舍去的操作,从而造成一次精度丢失。
  • 第二次在 0.1 和 0.2 转成二进制浮点数后,二进制浮点数相加的过程中,小数位相加导致小数位多出了一位,又要让第53位的数进行为1则进1为0则舍去的操作,又造成一次精度丢失。最终导致 0.1+0.2 不等于0.3 。

所以,在进行浮点数计算的时候,通常采用BigDecimal。

二、BigDecimal

老大,没搞错吧。

在这里插入图片描述

使用 BigDecimal 表示和计算浮点数,要使用字符串的构造方法来初始化 BigDecimal。

在这里插入图片描述

🏆哪吒多年工作总结:Java学习路线总结,搬砖工逆袭Java架构师。

JavaScript浮点数精度问题解析:0.1 + 0.2为什么不等于0.3 IEEE 754标准是由国际电气和电子工程师协会(IEEE)制定的一套关于浮点数运算的标准。该标准解决了不同计算机和处理器在进行浮点数计算时可能产生的不一致问题。由于早期计算机系统在浮点运算方面缺乏统一规范,导致同一个计算任务在不同的硬件或软件环境下得到的结果不尽相同,这对科学计算、工程、金融等领域造成了极大的困扰。IEEE 754标准的制定,使得浮点数的表示和运算在全世界范围内实现了标准化,极大地提高了计算结果的可移植性与可信度。Math对象包含了一系列用于执行基本数学运算和复杂数学计算的函数。 阅读详情

相关推荐

从CAD到完美网格:HyperMesh几何清理全流程指南(2023最新版)

本文详细介绍了2023最新版HyperMesh在几何清理和网格划分方面的全流程操作指南。从CAD导入、几何修复到中面提取和网格生成,系统性地分享了实战验证的解决方案,帮助工程师高效处理复杂几何体,提升有限元模型质量。特别针对汽车和航空航天领域的常见问题,提供了智能化工具和优化技巧。

weixin_29306011的博客 225

0.1+0.2 为什么不等于0.3

0.1+0.2的计算过程 1、十进制转成二进制 在JS内部所有的计算都是以二进制方式计算的。所以运算 0.1+ 0.2 时要先把 0.1和 0.2 从十进制转成二进制。 0.1转化成二进制的算法: 0.1*2=0.2======取出整数部分0 0.2*2=0.4======取出整数部分0 0.4*2=0.8======取出整数部分0 0.8*2=1.6======取出整数部分1 0.6*2=1.2======取出整数部分1 接下来会无限循环 0.2*2=0.4======取出整数部分..

cherryfef的博客 1万+

stm32f407等芯片(HAL库)时钟频率修改(乱码)

其他片子及库文件未知、未验证,只是在使用stm32f407ZG配置串口打印的时候,出现乱码,就从以下几方面定位问题: 1. 确认串口GPIO相关配置; 2. 确认波特率等参数; 3. 确认时钟频率; 结果这次使用YH的串口打印程序在ZDYZ的开发板调试项目工程(有点另类...),做功能验证,就出现了以上问题,出于好奇开始调试,最终发现是时钟频率问题。 看到下图这个配置,因为ZDYZ开发板使用的是8MHz外部晶振(好像默认的是25MHz,如图2),所以他这里PLL_M是25,不是推荐值,感...

bulefire2009的博客 5515

0.1 + 0.2 为什么不等于 0.3之小数精度问题

浮点数计算类,取二者中小数位数最长者(记为 N),同时乘以 10 的 N 次幂,转换为整数进行计算,再除以 N 次幂转回小数需要用 toFixed 取近似值的地方,可以先加上 1e-14 或 umber.EPSILON,再取。判定两个数字相等,可以使用 Math.abs(left - right) < Number.EPSILON实在不会,就直接用别人写好的成熟库吧。

yyh1994的博客 2103

YOLOv8实例分割实战:从LabelMe标注到模型训练全流程(附完整代码)

本文详细介绍了YOLOv8实例分割的完整实战流程,涵盖从使用LabelMe进行数据标注、格式转换,到构建数据集、配置参数并完成模型训练的全过程。文章提供了详尽的代码示例和常见问题解决方案,旨在帮助开发者高效掌握YOLOv8实例分割技术,快速应用于实际项目。

java5的博客 814

保姆级教程:在RV1126开发板上跑通YOLOv5口罩检测(从数据集到摄像头实时识别)

本文提供了一份详细的RV1126开发板部署YOLOv5口罩检测系统的全流程指南,涵盖数据集准备、模型训练优化、边缘部署及实时摄像头识别等关键步骤。重点解析了RV1126开发板的性能特征、YOLOv5模型训练调优技巧、RKNN模型转换量化策略,以及部署过程中的性能优化方案,帮助开发者高效实现边缘端目标检测应用。

weixin_27310985的博客 108

为什么 0.1 + 0.2 不等于0.3?如何解决这个问题?

一、开头 我们都知道0.1 + 0.2 !== 0.3,而是0.30000000000000004,那么是为什么?我们都知道计算机在内部实现中使用的是二进制,0.1也是不例外的,此时我们将0.1转换为二进制数据表示可以表示为:0.0001100110011001100...(1100无限循环),0.2转换为二进制数据可以表示为0.00110011001100...(1100循环),此时这两个数均为无限循环小数,那么该如何去存储呢? 二、如何存储二进制小数 不同的语言可能会有不同的存储标准,javascrip

weixin_47450807的博客 9108

LVGL在RTOS下的线程安全实践:从卡死到流畅的界面切换

本文探讨LVGL在RTOS环境下的线程安全实践,重点分析FreeRTOS多任务同步机制,包括互斥锁、任务通知和消息队列方案。通过实际案例展示如何避免界面卡顿和系统死锁,实现从卡死到流畅的界面切换,为嵌入式GUI开发提供可靠的适配解决方案。

uran的专栏 1111

如何理解 0.1+0.2

0.1 + 0.2 = 0.3 这是很多人都知道的事,但是,你的程序往往告诉你: 0.1 + 0.2 = 0.30000000000000004 不信你试试 那么,为什么? 你应该知道,十进制的 2,用二进制表示就是 10 这也是计算机存储 2 的方式 也就是我们需要两个“位”:一个位存 1,另一个存 0 用两个“位”,可以存四个数字,他们是: 00(十进制的 0) 01(十进制的 1) 10(十进制的 2) 11(十进制的 3) 我们买的 u 盘,经常说,是“2G 的”、“8G的.

大概关于 4075

f_fs.c 初始化流程(进行中)

前言 之所以选择f_fs.c作为这系列的开始,因为usb在/driver/usb下面的内容实在太多太多,如果讲各种各样点会太分散了。所以决定切入点以实际使用为主,就是f_fs了,目前我了解这是做bulk裸传输使用的,具体的通信协议自己确定。 初始化部分 开始点从这个路径下说起, /drivers/usb/gadget/function/f_fs.c 然后f_fs.c第一个使用的是include/composite.h中的宏定义function #define DECLARE_USB_FUNCTION(_n

weixin_36406973的博客 1967

2、探秘储备池计算:原理、应用与前沿趋势

储备池计算(Reservoir Computing)作为一种新兴的计算方法,起源于计算神经科学和机器学习领域,现已广泛应用于非线性动力系统理论、物理学、材料科学、生物学和机器人学等多个领域。其核心优势在于概念简洁性,通过利用高维动态系统的非线性响应,将学习过程集中在读出层,避免了传统循环神经网络(RNN)训练的复杂性。储备池计算的发展方向主要包括拓展到非线性动态系统和利用物理动态系统作为计算资源(PRC),后者有望突破冯·诺依曼瓶颈,实现边缘计算。理论方面,储备池计算与人类大脑的信息处理方式密切相关,并推动

ggg99的专栏 733

为什么 0.1+0.2=0.30000000000000004

0.1 和 0.2 是如何表示的? 根据前面的讲解,十进制 0.1 转为二进制小数,得到的是 0.0001100… (重复1100)这样一个循环二进制小数,使用 IEEE754 表示如下图:在浮点数的舍入问题上,IEEE 浮点格式定义了 4 种不同的舍入方式,如下表所示。其中,默认的舍入方法是向偶数舍入,而其他三种可用于计算上界和下界。同样的方法,0.2 用单精度浮点数表示是:0.20000000298023223876953125。所以,0.1 + 0.2 的结果是:0.30000000447034835

luoganttcc的博客 1427

基于网关实现不同网段S7-1200 CPU的通信方法

在A网段的计算机上ping B网段的计算机:在A网段的计算机上使用ping命令,向B网段的计算机发送数据包。在B网段的计算机上ping A网段的计算机:同样地,在B网段的计算机上使用ping命令,向A网段的计算机发送数据包。数据包也会经过路由器进行转发,最终到达A网段的计算机。配置路由器:在路由器上配置两个网段的IP地址和子网掩码,并设置路由表,使得路由器可以将A网段和B网段之间的数据进行转发。确定两个网络之间的路由器:假设需要将A网段和B网段进行通信,需要在A、B两个网段之间设置一台路由器。

电工 2399

python0.1+0.2不等于0.3_为什么0.1+0.2不等于0.3

先看两个简单但诡异的代码:0.1 + 0.2 > 0.3 // true0.1 * 0.1 = 0.0100000000000000020.1加0.2为什么就不等于0.3昵?要回答这个问题,得先了解计算机内部是如何表示数的。计算机内部如何表示数我们都知道,计算机用位来储存及处理数据。每一个二进制数(二进制串)都一一对应一个十进制数。1. 计算机内部如何表示整数这里以十进制数13来展示“按位计...

weixin_33617691的博客 5141

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

前端面试题——0.1+0.2为什么不等于0.3?

0.1+0.2=0.3在我们的日常生活中是简单到不用动脑子就能得出的等式。但是在计算机的世界中恐怕并非如此,你或许在编写代码时见过0.1+0.2=0.30000000000000004,是计算机算错了吗?让我们来探究其背后的原理。

omroji的博客 2039

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

python0.1+0.2不等于0.3_为什么0.1 + 0.2不等于0.3?

原标题:为什么0.1 + 0.2不等于0.3?0.1 + 0.2不等于0.3这是一个普遍的问题,例如在JS控制台输入将得到0.30000000000000004 在python的控制台也是输出这个数: 在C里面运行以下代码,指定输出小数位为57位:printf("%.57f", 0.1 + 0.2);将得到:0.3000000000000000444089209850062616169452667...

weixin_30800249的博客 1722

为什么0.1+0.2不等于0.3

首先来看一段诡异的代码: package org.sang.test; /** * @Author: chuxia0811 * @Date: 2021/2/9 22:55 * @Description : */ public class _01_02 { public static void main(String[] args) { float a = 0.1f; float b = 0.2f; System.out.println(a +

初夏0811的博客 2万+

0.1+0.2为什么不等于0.3,以及怎么等于0.3

在开发过程中遇到类似这样的问题: let n1 = 0.1, n2 = 0.2 console.log(n1 + n2) // 0.30000000000000004 这里得到的不是想要的结果,要想等于0.3,就要把它进行转化: (n1 + n2).toFixed(2) // 注意,toFixed为四舍五入 toFixed(num)方法可把 Number 四舍五入为指定小数位数的数字。那为什么会出现这样的结果呢?    计算机是通过二进制的方式存储数据的,所以计算机计算0.1+0.2的时候,实.

Front end development engineer 3万+

17、为什么0.1 + 0.2 不等于 0.3

再用2去除商,又会得到一个商和余数,如此进行,直到商为小于1时为止,然后把先得到的余数作为二进制数的低位有效位,后得到的余数作为二进制数的高位有效位,依次排列起来。具体做法是:用2乘十进制小数,可以得到积,将积的整数部分取出,再用2乘余下的小数部分,又得到一个积,再将积的整数部分取出,如此进行,直到积中的小数部分为零,此时0或1为二进制的最后一位。浮点数相加时,需要先比较指位数是否一致,如果一致则小数位直接相加,如果不一致,要先把指位数调成一致的,指位数小的向大的调整。转成浮点数形式的二进制。

天界程序员的博客 2287

为什么 JavaScript 中 0.1 0.2 不等于 0.3 ?

本文首发于 vivo互联网技术 微信公众号 链接:https://mp.weixin.qq.com/s/2kea7-jACCJmSYBQAwXyIg 作者:刘洋 在 js 中进行数学的运算时,会出现0.1+0.2=0.300000000000000004的结果,一开始认为是浮点数的二进制存储导致的精度问题,但这似乎不能很好的解释为什么在同样的存储方式下0.3+0.4=0.7可以得到正确的结...

vivo互联网技术 817

python中0.1+0.2为啥不等于0.3_为什么0.1+0.2不等于0.3?原来编程语言是这么算的……...

打开你的 Python,输入「0.1+0.2=」,结果是多少?0.30000000000000004 对不对?为什么结果不是 0.3?本文作者给出了详细的解释。从小我们就知道 0.1 + 0.2=0.3。但是,在光怪陆离的计算世界中,运算方式却大相径庭。我最近开始用 JavaScript 进行编码,在阅读数据类型时,我注意到 0.1 + 0.2 不等于 0.3 的奇怪行为。我向 Stack Ove...

weixin_34170028的博客 3912

为什么 0.1+0.2 不等于 0.3

位),而在这种格式下无法精确表示某些小数,因此在进行计算时会出现精度误差。中,这些小数会被转换成最接近它们的可表示值,然后再进行计算。被转换成的值可能会存在精度误差,导致它们的和不等于。都是无限循环小数,无法用二进制精确地表示。中采用的是双精度浮点数格式(

weixin_42560424的博客 3029

JS中为什么0.1+0.2 不等于0.3

科学计数法 假设有两个数字 220000000000 和 22000000000 一眼看过去好像很难比较出大小 但是使用科学计数法就非常容易进行比较 2.2∗10112.2∗1010 2.2*10^{11}\\ 2.2*10^{10} 2.2∗10112.2∗1010 IEEE 754浮点数表示 Javascript是使用双精度浮点数表示的。 sign:符号位 1表示数字为负数,0表示为正数 (1位) exponent:阶码 (11位) mantissa: 尾数 (52位) 总共64位 看不懂

ZHgogogoha的博客 806

在js里为什么0.1+0.2不等于0.3

在js里为什么0.1+0.2不等于0.31.产生原因2.内部原理扩展 1.产生原因 JS 采用的是双精度版本, 即IEEE 754 双精度版本(64位),这个版本就存在精度问题,就导致了上边这种情况。 在计算机中,数字无论是定点数还是浮点数都是以多位二进制的方式进行存储的。 2.内部原理 我们计算机的信息全部转化为二进制进行存储的,那么0.1的二进制表示的是一个无限循环小数,该版本的 JS 采用的是浮点数标准需要对这种无限循环的二进制进行截取,从而导致了精度丢失,造成了0.1不再是0.1,截取之后0.

cppp1111的博客 4034

为什么 Python 中0.1 + 0.2 不等于 0.3?

print(is_close(0.1 + 0.2, 0.3)) # 输出:True。

pythondh1的博客 2489
上一篇: 微服务 Spring Cloud 3,如何对微服务进行有效的监控?
下一篇: LinkedList的插入速度一定比ArrayList快吗?
哪 吒
哪 吒 2022年度博客之星TOP 1 2022年度博客之星TOP 1 领域专家: 后端开发技术领域 领域专家: 后端开发技术领域
博客等级 码龄9年 59万+粉丝 2939原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

哪 吒

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值