js中的0.1+0.2等于多少?为什么不等于0.3?

关于0.1+0.2,这是一个非常经典的问题

众所周知数学上是0.1+0.2是等于0.3的,然而在大部分编程语言中却不等于0.3

我第一次知道也是难以置信,于是就写了下图的java程序来验证

相信大部分小伙伴第一次知道这个事实后都会怀疑人生

难道这个世界是假的?我们身处在楚门的世界中?显然不是这样😂

这是为什么,又该如何解决呢?(本文以JAVA面试为例

PS:这个问题是一个比较有名的前端面试题,但实际上不止是JavaScript中,

后端的JAVA以及大部分别的语言都有这个问题

(题外话:

我对象也学计算机,大二的时候我和她打赌java里面0.1+0.2不等于0.3,她不信结果赌输了亲了我一下😁😁😁)

面试官:0.1+0.2等于多少?我:0.3000000000000004

面试官:为什么不是0.3?我:不知道...... 结果直接回家等通知

许多开发者知道0.1+0.2==0.3000000000000004

却是知其然不知其所以然,这里我简单说说为什么0.1+0.2不等于0.3

众所周知计算机使用的是二进制

十进制小数转成二进制,一般采用"乘2取整,顺序排列"方法,如0.625转成二进制的表示为0.101。 但是,并不是所有小数都能转成二进制,如0.1就不能直接用二进制表示,他的二进制是0.000110011001100... 这是一个无限循环小数。所以,计算机是没办法用二进制精确的表示0.1的
人们想出了一种采用一定的精度,使用近似值表示一个小数的办法。这就是IEEE 754

IEEE754中,一个浮点数由符号位、尾数和阶码组成。符号位用于表示正数或负数,尾数是有效数字的部分,而阶码用于表示指数

十进制数经IEEE754实际转换得到的二进制数是一个近似值
而Double类型只存储8字节,即64位 ,如下图所示
0.1转换为

复制代码

0 1111111011 1001100110011001100110011001100110011001100110011001

0.2转换为

复制代码

0 01111111100 1001100110011001100110011001100110011001100110011010

相加得

复制代码

0 01111111101 0011001100110011001100110011001100110011001100111010

故转换成十进制就得0.3000000000000004

面试官:0.1+0.2等于多少?我:0.3000000000000004

面试官:为什么不是0.3?我:因为采用了IEEE754码制,十进制浮点数无法完全精确转换为二进制浮点数

面试官:那你能实现0.1+0.2==0.3吗 我:我不会欸.. 结果直接回家等通知

面试官:0.1+0.2等于多少?我:0.3000000000000004

面试官:为什么不是0.3?我:因为采用了IEEE754码制,十进制浮点数无法精确转换为二进制浮点数

面试官:那你能否实现0.1+0.2==0.3

我:(0.1* 10 + 0.2 *10)/10==0.3

其实想要使0.1+0.2等于0.3也是可以实现的 最简单的方法就是
(0.1* 10 + 0.2 *10)/10==0.3

直接乘10再除以10 就好了,因为乘以10以后就是整数运算了,就是精确值了

但在实际的业务场景中却并不是一个很好的办法

面试官:你还会别的实现方法吗

我:使用BigDecimal类存储0.1和0.2,然后再用add方法相加!

面试官:下周来入职🤝🤝🤝!

针对0.1+0.2问题,java中常用的解决方法BigDecimal

BigDecimal 是一个可以实现对浮点数的运算的类,而且不会造成精度丢失

复制代码

import java.math.BigDecimal; public class Main{ public static void main(String[] args) { BigDecimal a = new BigDecimal("0.1"); BigDecimal b = BigDecimal.valueOf(0.2); BigDecimal c = a.add(b); System.out.println(c); } }

(终于等于0.3了,呼~)

需要注意的是BigDecimal的用法,以上文字引用自《阿里巴巴开发手册》

有的人看完了可能会说,差这么一点点有什么关系呢

实际上如果涉及到高频金钱交易的话,这一点点的差距也可以造成致命的损失

比如某金融系统可能1天交易100万次,1次损失1分钱,一个月下来损失就有30万了!

希望兄弟们遇到类似的场景不要忘记BigDecimal的用法,记得不要直接传参数

相关推荐
2601_962071571 小时前
【Java报错已解决】org.springframework.beans.factory.BeanCreationException
java·开发语言
香芋芋圆2 小时前
AI 冲击内卷之下,普通前端如何破局?WebGIS—— 低门槛突围赛道
前端·javascript·人工智能·学习·职场发展
INS_KF2 小时前
【编程笔记】成员函数中两个 const 的区别(const Data &getData() const;)
前端·javascript·笔记
淡海水2 小时前
07-04-并发-ConcurrentBag-T-工作窃取WorkStealing算法
开发语言·算法·c#·bag·concurrent·workstealing
宿6743 小时前
vue3-async
前端·javascript·vue.js
CS_Zero3 小时前
C语言sizeof是函数吗?
c语言·开发语言
-今昭-4 小时前
《V2V 迁移实战:将 VMware 虚拟机转为 OpenStack 可用 Glance qcow2 镜像》
开发语言·python
excel4 小时前
Nuxt + Twin CSS 中宽度超过屏幕时底部出现空白的原因与解决方案
前端·javascript
黑马程序员毕设5 小时前
基于Java的医院药品管理系统的优化设计与实现
java·开发语言·spring boot·小程序·架构·课程设计·毕设
_Twink1e6 小时前
openJiuwen 实训营 Day 1 · WorkSwarm 入门教程
开发语言·c++·openjiuwen