0.1+0.2不等于0.3的真相 - 计算机浮点数运算的秘密

探究浮点数精度问题:为何 0.1 + 0.2 不等于 0.3

浮点数精度问题

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

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

编程语言在计算0.1 + 0.2的结果-1

编程语言在计算0.1 + 0.2的结果-2

编程语言在计算0.1 + 0.2的结果-3

编程语言在计算0.1 + 0.2的结果-4

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

JavaScript演示

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

JavaScript演示结果

还有其他的例子:

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标准

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

在二进制中,浮点数通常使用 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 为例,来理解二进制和十进制的表示:

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.1 转化为二进制

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

0.2 = 0.001100110011001100110011001100110011001100110011001101...

十进制小数0.2 转化为二进制

解决办法

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 地址:https://github.com/MikeMcl/decimal.js

首先,你需要在你的项目中引入 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 中的近似值。文章来源地址https://www.toymoban.com/diary/system/758.html

到此这篇关于0.1+0.2不等于0.3的真相 - 计算机浮点数运算的秘密的文章就介绍到这了,更多相关内容可以在右上角搜索或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

原文地址:https://www.toymoban.com/diary/system/758.html

如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请联系站长进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用
解决Safari以及iOS上的其他浏览器子元素不受border-radius作用的问题
上一篇 2024年04月08日 15:19
小米14怎么关闭5G网络(小白教程)
下一篇 2024年04月11日 14:36

相关文章

  • 为什么 0.1+0.2 不等于 0.3

    62. 为什么 0.1+0.2 不等于 0.3 在 JavaScript 中, 0.1 + 0.2 的结果不等于 0.3 ,这是因为在 JavaScript 中采用的是双精度浮点数格式( 64 位),而在这种格式下无法精确表示某些小数,因此在进行计算时会出现精度误差。 具体来说, 0.1 和 0.2 都是无限循环小数,无法用二进制精确地表

    2024年02月08日
    浏览(31)
  • 关于js中0.1+0.2不等于0.3的问题

    在 js中,有时候你可能会发现 0.1+0.2 不等于 0.3 。这是因为 js使用的是浮点数来表示小数,而浮点数在计算机内部是用二进制表示的,这导致了一些精度问题。 例如,在 js中, 0.1 实际上是一个近似值,而不是精确值。它的实际值是这样的: 同样地, 0.2 也是一个近似值,它

    2024年02月13日
    浏览(34)
  • 为什么JS中0.1+0.2不等于0.3

    当我们在计算机中使用浮点数进行计算时,特别是在使用二进制表示浮点数时,可能会出现舍入误差。这是由于计算机使用有限的位数来表示浮点数,而某些十进制数无法精确地表示为有限的二进制数。 0.1 和 0.2 都是无限循环的二进制数,在转换为浮点数时并不能完全准确地

    2024年02月07日
    浏览(30)
  • 为什么 JavaScript 中的 0.1 + 0.2 不等于 0.3

    本文作者为 360 奇舞团前端开发工程师 在使用 JavaScript 处理运算时,有时会碰到数字运算结果不符合预期的情况,比如经典的 0.1 + 0.2 不等于 0.3。当然这种问题不只存在于 JavaScript,不过编程语言的一些原理大致相通,我以 JavaScript 为例解释这种问题,并说明前端如何尽可能

    2024年03月13日
    浏览(38)
  • 【计算机组成原理】IEEE 754 标准定义的浮点数表示格式

    IEEE 754是一种由美国电气和电子工程师协会(IEEE)制定的标准,用于定义浮点数的表示和运算。这个标准定义了浮点数的格式、舍入规则、特殊值的处理以及算术操作的执行方式。 IEEE 754浮点数标准主要定义了两种浮点数格式:单精度浮点数和双精度浮点数。单精度浮点数占

    2024年01月22日
    浏览(24)
  • [Python]补充程序实现以下计算小明参加语文,数学和英语考试,输入小明的3门课程考试成绩,计算并输出3门课程考试成绩的和、平均值以及最高和最低分。 如果三门课程以权重0.5,0.3和0.2计入总分

    补充程序实现以下计算 小明参加语文,数学和英语考试,输入小明的3门课程考试成绩,计算并输出3门课程考试成绩的和、平均值以及最高和最低分。 如果三门课程以权重0.5,0.3和0.2计入总分,计算并输出小明的最终总评成绩。 输入样例: 输出样例:

    2024年03月14日
    浏览(31)
  • 计算机组成原理之计算机硬件发展和计算机系统的组成

    学习的最大理由是想摆脱平庸,早一天就多一份人生的精彩;迟一天就多一天平庸的困扰。各位小伙伴,如果您: 想系统/深入学习某技术知识点… 一个人摸索学习很难坚持,想组团高效学习… 想写博客但无从下手,急需写作干货注入能量… 热爱写作,愿意让自己成为更好

    2024年01月24日
    浏览(23)
  • 计算机基础--计算机存储单位

    计算机中表示文件大小、数据载体的存储容量或进程的数据消耗的信息单位。在计算机内部,信息都是釆用二进制的形式进行存储、运算、处理和传输的。信息存储单位有位、字节和字等几种。各种存储设备存储容量单位有KB、MB、GB和TB等几种。 位(bit):二进制数中的一个

    2024年02月03日
    浏览(23)
  • 计算机前沿(2022计算机前沿方向)

    时刻关注前沿研究方向,目前计算机前沿研究方向主要有一下几种。 机器智能,数据计算,机器人,金融科技,量子计算机,高端芯片,6G通信等。 在人工智能领域,基本是通过计算机来模拟人的听,说,读,写,看和脑子决策。 听(语音识别) 说(语音识别) 读(语音识

    2024年02月10日
    浏览(20)
  • 计算机组成原理-计算机系统概述

    目录 一,基本组成  二、各部件工作原理 2.1存储器 2.2运算器  2.3控制器  2.4输入设备 2.5输出设备 一条指令的工作原理  三、计算机系统的层次结构  三种基本语言 四、计算机性能指标         “存储程序”的概念,指将指令以二进制代码的形式事先输入计算机的主存

    2024年02月05日
    浏览(21)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包