浮点数值计算精度丢失问题剖析及解决方法
文章目录
- 1、原因分析
- 2、解决方法
- 2.1、Java中使用 BigDecimal 类
- 2.2、JavaScript 中解决计算精度丢失的问题
- 3、使用建议
1、原因分析
首先我们来看个反直觉的浮点数值计算
System.out.println(0.3*3);
有的同学可能要问为啥不是0.9?
首先要知道为什么会产生这个问题?我们知道计算机的底层世界都是由0和1组成的,而浮点数值就是采用二进制系统表示,常见两种基本的浮点类型: float 和 double。
其中单精度float为32位浮点数,1位符号,8位指数和23位尾数(小数部分)。
双精度double则为64位浮点数,1位符号,11位指数和52位尾数(小数部分)。
接下来我们先看下十进制小数转二进制的例子,例如将 0.3 转为二进制
0.3*2=0.6 //取整数0
0.6*2=1.2 //取整数1
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 //取整数0
0.4*2=0.8 //取整数0
0.8*2=1.6 //取整数1
......
二进制表示为:010011001......
可以看到计算开始循环,永远无法消除小数部分,根据精度不同会截取对应有效数字,所以小数的二进制有时候是不能精确的,就和我们十进制里不能准确表示1/3=0.33333333…是一个道理。
这种情况在计算时会造成了精度丢失,也就是舍入误差,对于金额计算会产生严重的后果。
2、解决方法
2.1、Java中使用 BigDecimal 类
我们先看下Java里面的BigDecimal类,构造方法如下
可以看到 BigDecimal 有好几个构造方法,BigDecimal(int)、BigDecimal(double)、BigDecimal(String)等,但是这里要保证精度不丢失,构造参数不要用double类型,因为double类型传入的时候本身就是不完全精确的。如下:
BigDecimal bd1=new BigDecimal("0.3");
BigDecimal bd2=new BigDecimal("3");
BigDecimal bd3=new BigDecimal(3);
System.out.println(bd1.multiply(bd2));
System.out.println(bd1.multiply(bd3));
扩展:在金融领域,也可以使用一些第三方库,例如
<dependency><groupId>org.javamoney</groupId><artifactId>moneta</artifactId><version>1.1</version>
</dependency>
里面的Money类对金额做了显性的抽象,增加了金额的单位,避免了直接使用 BigDecimal 踩一些坑。
2.2、JavaScript 中解决计算精度丢失的问题
解决方法:decimal.js
decimal.js为 JavaScript 提供十进制类型的任意精度数值,是使用的二进制来计算的,所以能解决js的精度问题。
官网:http://mikemcl.github.io/decimal.js
GitHub地址:https://github.com/MikeMcl/decimal.js
用法如下:
<!DOCTYPE html>
<html><head><meta charset="utf-8"><title></title></head><body><script src='js/decimal.js'></script><script type="text/javascript">var a=0.3*3;console.log(a);var b=0.1+0.2;console.log(b);//使用decimallet a1 = new Decimal(0.3).mul(new Decimal(3));console.log(a1.toNumber());let b2 = new Decimal(0.1).add(new Decimal(0.2));console.log(b2.toNumber());</script></body>
</html>
结果如下:
// 加法
let c = new Decimal(a).add(new Decimal(b));
// 减法
let d = new Decimal(a).sub(new Decimal(b));
// 乘法
let e = new Decimal(a).mul(new Decimal(b));
// 除法
let f = new Decimal(a).div(new Decimal(b));
3、使用建议
针对浮点数值存储和计算,大佬超给大家简单罗列了以下几点看法,欢迎补充。
-
禁止通过判断两个浮点数是否相等来控制某些业务流程:在比较浮点数时,由于存在误差,往往会出现意料之外的结果。
-
整型存储其最小单位的值:在要求绝对精确表示的业务场景下,比如金融行业的货币表示,展示时可以转换成该货币的常用单位,比如人民币使用分存储,美元使用美分存储。
-
数组保存小数部分的数据:在要求精确表示小数点位的业务场景下,比如圆周率要求存储小数点后 1000 位数字,使用单精度和双精度浮点数类型保存是难以做到的。
-
数据库中保存小数时,推荐使用 decimal 类型。
更多技术干货,请持续关注程序员大佬超。
原创不易,转载请注明出处。
相关文章:

浮点数值计算精度丢失问题剖析及解决方法
文章目录1、原因分析2、解决方法2.1、Java中使用 BigDecimal 类2.2、JavaScript 中解决计算精度丢失的问题3、使用建议1、原因分析 首先我们来看个反直觉的浮点数值计算 System.out.println(0.3*3);有的同学可能要问为啥不是0.9? 首先要知道为什么会产生这个问题…...

字符串匹配 - 模式预处理:朴素算法(Naive)(暴力破解)
朴素的字符串匹配算法又称为暴力匹配算法(Brute Force Algorithm),最为简单的字符串匹配算法。算法简介朴素的字符串匹配算法又称为暴力匹配算法(Brute Force Algorithm),它的主要特点是:没有预…...

CVE-2021-42278 CVE-2021-42287域内提权漏洞
漏洞介绍2021 年 11 月 9 日,国外研究员在推特上发布了AD相关的 CVE,CVE-2021-42278 & CVE-2021-42287 ,两个漏洞组合可导致域内普通用户权限提升至域管权限。CVE-2021-42278:是一个安全绕过漏洞,允许通过修改机器…...

关于IcmpSendEcho2的使用和回调问题
由于我的需求是短时间内ping多台机子,所以需要异步执行,微软提供的例子是同步方式的,根据微软官方提供的icmpSendEcho2 函数的信息 ,我需要定义一个空的宏PIO_APC_ROUTINE_DEFINED ,定义完之后,编译又出现…...
XQuery 术语
在 XQuery 中,有七种节点:元素、属性、文本、命名空间、处理指令、注释、以及文档节点(或称为根节点)。 XQuery 术语 节点 在 XQuery 中,有七种节点:元素、属性、文本、命名空间、处理指令、注释、以及文…...

会议论文分享-Security22-状态感知符号执行
Ferry: State-Aware Symbolic Execution for Exploring State-Dependent Program Paths1.引言2.问题陈述与分析2.1.实现状态感知符号执行的挑战2.2.真实程序的特征2.3.Ferry的模型2.3.1.程序状态的定义2.3.2.状态描述变量的特征3.Design3.1.Overview of Ferry3.2.状态描述变量识…...

吴恩达深度学习笔记(八)——卷积神经网络(上)
一、卷积相关 用一个ff的过滤器卷积一个nn的图像,假如padding为p,步幅为s,输出大小则为: [n2p−fs1][n2p−fs1][\frac{n2p-f}{s}1][\frac{n2p-f}{s}1][sn2p−f1][sn2p−f1] []表示向下取整(floor) 大部分深度学习…...

14 基数排序(桶排序)
文章目录1 基数排序基本思想2 基数排序的代码实现2.1 java2.2 scala3 基数排序总结1 基数排序基本思想 1) 基数排序(radix sort)属于“分配式排序”(distribution sort),又称“桶子法”(bucket sort&#…...
汉明距离Java解法
两个整数之间的 汉明距离 指的是这两个数字对应二进制位不同的位置的数目。 给你两个整数 x 和 y,计算并返回它们之间的汉明距离。 例: 输入:x 1, y 4 输出:2 解释: 1 (0 0 0 1) 4 (0 1 0 0) ↑ ↑ 上…...

Netty服务端请求接受过程源码剖析
目标 服务器启动后,客户端进行连接,服务器端此时要接受客户端请求,并且返回给客户端想要的请求,下面我们的目标就是分析Netty 服务器端启动后是怎么接受到客户端请求的。我们的代码依然与上一篇中用同一个demo, 用io.…...

金三银四春招特供|高质量面试攻略
🔰 全文字数 : 1万5千 🕒 阅读时长 : 20min 📋 关键词 : 求职规划、面试准备、面试技巧、谈薪职级 👉 公众号 : 大摩羯先生 本篇来聊聊一个老生常谈的话题————“面试”。利用近三周工作午休时间整理了这篇洋洋洒洒却饱含真诚…...

搭建Hexo博客-第4章-绑定自定义域名
搭建Hexo博客-第4章-绑定自定义域名 搭建Hexo博客-第4章-绑定自定义域名 搭建Hexo博客-第4章-绑定自定义域名 在这一篇文章中,我将会介绍如何给博客绑定你自己的域名。其实绑定域名本应该很简单的,但我当初在这上走了不少弯路,所以我觉得有…...
lightdb-sql拦截
文章目录LightDB - sql 审核拦截一 简介二 参数2.1 lightdb_sql_mode2.2 lt_firewall.lightdb_business_time三 规则介绍及使用3.1 select_without_where3.1.1 案例3.2 update_without_where/delete_without_where3.2.1 案例3.3 high_risk_ddl3.3.1 案例LightDB - sql 审核拦截…...

二进制中1的个数-剑指Offer-java位运算
一、题目描述编写一个函数,输入是一个无符号整数(以二进制串的形式),返回其二进制表达式中数字位数为 1 的个数(也被称为 汉明重量).)。提示:请注意,在某些语言(如 Java&…...

学自动化测试可以用这几个练手项目
练手项目的业务逻辑比较简单,只适合练手,不能代替真实项目。 学习自动化测试最难的是没有合适的项目练习。 测试本身既要讲究科学,又有艺术成分,单单学几个 api 的调用很难应付工作中具体的问题。 你得知道什么场景下需要添加显…...

2023年保健饮品行业分析:市场规模不断攀升,年度销额增长近140%
随着人们健康意识的不断增强,我国保健品市场需求持续增长,同时,保健饮品的市场规模也在不断攀升。 根据鲸参谋电商数据显示,2022年度,京东平台上保健饮品的年度销量超60万件,同比增长了约124%;该…...

2023-02-17 学习记录--TS-邂逅TS(一)
TS-邂逅TS(一) 不积跬步,无以至千里;不积小流,无以成江海。💪🏻 一、TypeScript在线编译器 https://www.typescriptlang.org/play/ 二、类型 1、普通类型 number(数值型ÿ…...

SpringMVC创建异步回调请求的4种方式
首先要明确一点,同步请求和异步请求对于客户端用户来讲是一样的,都是需客户端等待返回结果。不同之处在于请求到达服务器之后的处理方式,下面用两张图解释一下同步请求和异步请求在服务端处理方式的不同:同步请求异步请求两个流程…...

MySQL(二)表的操作
一、创建表 CREATE TABLE table_name ( field1 datatype, field2 datatype, field3 datatype ) character set 字符集 collate 校验规则 engine 存储引擎; 说明: field 表示列名 datatype 表示列的类型 character set 字符集,如…...

SpringCloud - 入门
目录 服务架构演变 单体架构 分布式架构 分布式架构要考虑的问题 微服务 初步认识 案例Demo 服务拆分注意事项 服务拆分示例 服务调用 服务架构演变 单体架构 将业务的所有功能集中在一个项目中开发,打成一个包部署优点: 架构简单部署成本低缺…...

(十)学生端搭建
本次旨在将之前的已完成的部分功能进行拼装到学生端,同时完善学生端的构建。本次工作主要包括: 1.学生端整体界面布局 2.模拟考场与部分个人画像流程的串联 3.整体学生端逻辑 一、学生端 在主界面可以选择自己的用户角色 选择学生则进入学生登录界面…...
三维GIS开发cesium智慧地铁教程(5)Cesium相机控制
一、环境搭建 <script src"../cesium1.99/Build/Cesium/Cesium.js"></script> <link rel"stylesheet" href"../cesium1.99/Build/Cesium/Widgets/widgets.css"> 关键配置点: 路径验证:确保相对路径.…...

Python:操作 Excel 折叠
💖亲爱的技术爱好者们,热烈欢迎来到 Kant2048 的博客!我是 Thomas Kant,很开心能在CSDN上与你们相遇~💖 本博客的精华专栏: 【自动化测试】 【测试经验】 【人工智能】 【Python】 Python 操作 Excel 系列 读取单元格数据按行写入设置行高和列宽自动调整行高和列宽水平…...

通过Wrangler CLI在worker中创建数据库和表
官方使用文档:Getting started Cloudflare D1 docs 创建数据库 在命令行中执行完成之后,会在本地和远程创建数据库: npx wranglerlatest d1 create prod-d1-tutorial 在cf中就可以看到数据库: 现在,您的Cloudfla…...

centos 7 部署awstats 网站访问检测
一、基础环境准备(两种安装方式都要做) bash # 安装必要依赖 yum install -y httpd perl mod_perl perl-Time-HiRes perl-DateTime systemctl enable httpd # 设置 Apache 开机自启 systemctl start httpd # 启动 Apache二、安装 AWStats࿰…...

vscode(仍待补充)
写于2025 6.9 主包将加入vscode这个更权威的圈子 vscode的基本使用 侧边栏 vscode还能连接ssh? debug时使用的launch文件 1.task.json {"tasks": [{"type": "cppbuild","label": "C/C: gcc.exe 生成活动文件"…...
Go 语言接口详解
Go 语言接口详解 核心概念 接口定义 在 Go 语言中,接口是一种抽象类型,它定义了一组方法的集合: // 定义接口 type Shape interface {Area() float64Perimeter() float64 } 接口实现 Go 接口的实现是隐式的: // 矩形结构体…...

Linux --进程控制
本文从以下五个方面来初步认识进程控制: 目录 进程创建 进程终止 进程等待 进程替换 模拟实现一个微型shell 进程创建 在Linux系统中我们可以在一个进程使用系统调用fork()来创建子进程,创建出来的进程就是子进程,原来的进程为父进程。…...

九天毕昇深度学习平台 | 如何安装库?
pip install 库名 -i https://pypi.tuna.tsinghua.edu.cn/simple --user 举个例子: 报错 ModuleNotFoundError: No module named torch 那么我需要安装 torch pip install torch -i https://pypi.tuna.tsinghua.edu.cn/simple --user pip install 库名&#x…...

安全突围:重塑内生安全体系:齐向东在2025年BCS大会的演讲
文章目录 前言第一部分:体系力量是突围之钥第一重困境是体系思想落地不畅。第二重困境是大小体系融合瓶颈。第三重困境是“小体系”运营梗阻。 第二部分:体系矛盾是突围之障一是数据孤岛的障碍。二是投入不足的障碍。三是新旧兼容难的障碍。 第三部分&am…...