java大量浮点数如何作比较,Java如何正确比较浮点数
看下面这段代码,将 d1 和 d2 两个浮点数进行比较,输出的结果会是什么?
double d1 = .1 * 3;
double d2 = .3;
System.out.println(d1 == d2);
按照正常逻辑来看,d1经过计算之后的结果应该是0.3,最后打印的结果应该是 true,对吧?但是运行一下就会发现结果并不是 true 而是 false 。
输出一下 d1,发现得到的答案不是想象中的 0.3 而是 0.30000000000000004,所以和 d2 进行比较结果自然是 false
如何正确地比较浮点数(单精度的 float 和双精度的 double),不单单是 Java 特定的问题,在计算机的内存中,存储浮点数时使用的是 IEEE 754 标准,就会有精度的问题。
存储和转换的过程中浮点数容易引起一些较小的舍入误差,正是这个原因,导致在比较浮点数的时候,不能使用“==”操作符——要求严格意义上的完全相等。
那么如何正确的比较浮点数呢?这里有两种方案。
第一种方案是允许两个值之间存在一点误差(指定一个阈值),使用 Math.abs() 方法来计算两个浮点数之间差异的绝对值,如果这个差异在阈值范围之内,我们就认为两个浮点数是相等的。
final double THRESHOLD = .0001;
double d1 = .1 * 3;
double d2 = .3;
if(Math.abs(d1-d2) < THRESHOLD) {
System.out.println("d1 和 d2 相等");
} else {
System.out.println("d1 和 d2 不相等");
}
Math.abs() 方法用来返回 double 的绝对值,如果 double 小于 0,则返回 double 的正值,否则返回 double。也就是说,abs() 后的结果绝对大于 0,如果结果小于阈值(THRESHOLD),我们就认为 d1 和 d2 相等。
第二种方案是使用 BigDecimal 类,可以指定要舍入的模式和精度,这样就可以解决舍入的误差。
以使用 BigDecimal 类的 compareTo() 方法对两个数进行比较,该方法将会忽略小数点后的位数,怎么理解这句话呢?比如说 2.0 和 2.00 的位数不同,但它俩的值是相等的。
a.compareTo(b) 如果 a 和 b 相等,则返回 0,否则返回 -1。
tips: 不要使用 equals() 方法对两个 BigDecimal 对象进行比较,这是因为 equals() 方法会考虑位数,如果位数不同,则会返回 false,尽管数学值是相等的。
BigDecimal a = new BigDecimal("2.00");
BigDecimal b = new BigDecimal("2.0");
System.out.println(a.equals(b));
System.out.println(a.compareTo(b) == 0);
上面的代码中 a.equals(b) 的结果就为 false,因为 2.00 和 2.0 小数点后的位数不同,但 a.compareTo(b) == 0 的结果就为 true,因为 2.00 和 2.0 在数学层面的值的确是相等的。
compareTo() 方法比较的过程非常严谨,源码如下:
private int compareMagnitude(BigDecimal val) {
// Match scales, avoid unnecessary inflation
long ys = val.intCompact;
long xs = this.intCompact;
if (xs == 0)
return (ys == 0) ? 0 : -1;
if (ys == 0)
return 1;
long sdiff = (long)this.scale - val.scale;
if (sdiff != 0) {
// Avoid matching scales if the (adjusted) exponents differ
long xae = (long)this.precision() - this.scale; // [-1]
long yae = (long)val.precision() - val.scale; // [-1]
if (xae < yae)
return -1;
if (xae > yae)
return 1;
if (sdiff < 0) {
// The cases sdiff <= Integer.MIN_VALUE intentionally fall through.
if ( sdiff > Integer.MIN_VALUE &&
(xs == INFLATED ||
(xs = longMultiplyPowerTen(xs, (int)-sdiff)) == INFLATED) &&
ys == INFLATED) {
BigInteger rb = bigMultiplyPowerTen((int)-sdiff);
return rb.compareMagnitude(val.intVal);
}
} else { // sdiff > 0
// The cases sdiff > Integer.MAX_VALUE intentionally fall through.
if ( sdiff <= Integer.MAX_VALUE &&
(ys == INFLATED ||
(ys = longMultiplyPowerTen(ys, (int)sdiff)) == INFLATED) &&
xs == INFLATED) {
BigInteger rb = val.bigMultiplyPowerTen((int)sdiff);
return this.intVal.compareMagnitude(rb);
}
}
}
if (xs != INFLATED)
return (ys != INFLATED) ? longCompareMagnitude(xs, ys) : -1;
else if (ys != INFLATED)
return 1;
else
return this.intVal.compareMagnitude(val.intVal);
}
接下来,用 BigDecimal 来解决开头的问题。
BigDecimal d1 = new BigDecimal("0.1");
BigDecimal three = new BigDecimal("3");
BigDecimal d2 = new BigDecimal("0.3");
d1 = d1.multiply(three);
System.out.println("d1 = " + d1);
System.out.println("d2 = " + d2);
System.out.println(d1.compareTo(d2));
程序输出的结果如下:
d1 = 0.3
d2 = 0.3
0
d1 和 d2 都为 0.3,所以 compareTo() 的结果就为 0,表示两个值是相等的。
总结一下,在遇到浮点数的时候,千万不要使用 == 操作符来进行比较,因为有精度问题。要么使用阈值来忽略舍入的问题,要么使用 BigDecimal 来替代 double 或者 float。
java大量浮点数如何作比较,Java如何正确比较浮点数相关推荐
- ictclas java_ICTCLAS50 基于中科院分词作的java 工具,内容详细各个函数都有实现 含有word解析文档 Develop 238万源代码下载- www.pudn.com...
文件名称: ICTCLAS50下载 收藏√ [ 5 4 3 2 1 ] 开发工具: Java 文件大小: 2983 KB 上传时间: 2013-05-15 下载次数: 11 提 供 者: 安 ...
- 毕业一年的大专生程序员工作总结(java后台)
文章导读 一.回眸过去 – 闲扯的话 – 零碎的技术 二.经验总结 – 沟通交流 – 贵在坚持 – 合理规划 三.展望未来 – 积累行业背景 – 学习清单 四.最后补充 一. 回牟过去 1.闲扯的话 ...
- 浮点数0.7在Java中是无法精确存储的,却为何能精确输出0.7
2019独角兽企业重金招聘Python工程师标准>>> 这是在其他地方看到的一个提问,提问原文链接:https://www.oschina.net/question/2346828_ ...
- Java中如何正确进行浮点数运算
1.浮点数不是精确存储 参考: 关于浮点数存储 System.out.println(0.1+0.2);System.out.println(1.0-0.8);System.out.println(4 ...
- 描述java源程序构成_Java第二章Java程序设计
<Java第二章Java程序设计>由会员分享,可在线阅读,更多相关<Java第二章Java程序设计(140页珍藏版)>请在人人文库网上搜索. 1.第2章 Java基本语法,2. ...
- Java程序设计语言基础02:Java中的基本数据类型和运算符
目录 1. Java中的基本数据类型 1.1 概述 1.2 基本数据类型的值域 1.2.1 byte类型 1.2.2 short类型 1.2.3 int类型 1.2.4 long类型 1.2.5 fl ...
- Java复习总结(二)Java SE 面试题
Java SE基础知识 目录 Java SE 1. 请你谈谈Java中是如何支持正则表达式操作的? 2. 请你简单描述一下正则表达式及其用途. 3. 请你比较一下Java和JavaSciprt? 4. ...
- Java面试准备(一)——Java基础
Java基础 一.基础概念与常识 1. Java和C++对比 2. Java语言有哪些特点 3. 什么是字节码?采用字节码的好处? 4. JVM,JRE和JDK 5. Oracle JDK和OpenJ ...
- 学习笔记(11):Java小白修炼手册-一句话在Java中如何表达?快学Java字符串
立即学习:https://edu.csdn.net/course/play/27274/361060?utm_source=blogtoedu 1 JDK Java语言的开发包(开发使用) JRE J ...
最新文章
- 呼叫中心最难的问题是什么?
- tf.reduce_mean tf.reduce_sum优化目标函数时如何选择
- 算法(5) 归并排序
- ppct各代表什么_开关背面L、L1、L2各代表什么?火线,零线,地线怎样接?
- matlab安装_走进数模(三)MATLAB安装
- hihoCoder #1467 : 2-SAT·hihoCoder音乐节
- SAP Spartacus加载delivery region的实现
- python获取绝对路径的区别_python 获取路径不同方法的比较
- 在Google使用Borg进行大规模集群的管理 5-6
- 中事件源previous_PM2.5传感器在扬尘监测系统中的应用
- Ionic 开发环境搭建
- eclipse:STS下载使用(STS(Spring Tool Suite)其实是个被包装过的eclipse)
- 程序读取凡人修仙传热度数据
- Excel中截取特殊字符之前、之间、之后的数据
- pytorch中F.avg_pool1d()和F.avg_pool2d()
- 【数智化案例展】某头部股份制银行总行——“数字化投顾”工作台
- Android WallpaperManager 同时设置桌面壁纸与锁屏的问题
- (附源码)spring boot校园拼车微信小程序 毕业设计 091617
- 截图工具snipaste安装和使用
- 英伟达显卡笔记本如何免费获得2k甚至4k屏幕
热门文章
- c++11或c++14或c++17参数包的使用
- EntityFramework进阶——CodeFirst数据库迁移
- latex插入图片之后出现大段空白,并且紧随其后的文字如同被覆盖一般不见了
- java asynchronize_Java 中synchronize函数的实例详解
- 华硕主板专用Ghost Win11 64位专业体验版 V2021.08
- 微服务系列之ZooKeeper注册中心和Nacos注册中心Nacos和Zookeeper对比
- URL传Base64 造成报错 Illegal base64 character 20
- Java微服务篇4——Elastic search
- sqldataadapter.fill 索引超出了数组界限_小学生学习C++||第十五节 数组
- pythonsql注入步骤_防止SQL注入解决方案