看下面这段代码,将 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如何正确比较浮点数相关推荐

  1. ictclas java_ICTCLAS50 基于中科院分词作的java 工具,内容详细各个函数都有实现 含有word解析文档 Develop 238万源代码下载- www.pudn.com...

    文件名称: ICTCLAS50下载 收藏√  [ 5  4  3  2  1 ] 开发工具: Java 文件大小: 2983 KB 上传时间: 2013-05-15 下载次数: 11 提 供 者: 安 ...

  2. 毕业一年的大专生程序员工作总结(java后台)

    文章导读 一.回眸过去 – 闲扯的话 – 零碎的技术 二.经验总结 – 沟通交流 – 贵在坚持 – 合理规划 三.展望未来 – 积累行业背景 – 学习清单 四.最后补充 一. 回牟过去 1.闲扯的话 ...

  3. 浮点数0.7在Java中是无法精确存储的,却为何能精确输出0.7

    2019独角兽企业重金招聘Python工程师标准>>> 这是在其他地方看到的一个提问,提问原文链接:https://www.oschina.net/question/2346828_ ...

  4. Java中如何正确进行浮点数运算

    1.浮点数不是精确存储 参考: 关于浮点数存储 System.out.println(0.1+0.2);System.out.println(1.0-0.8);System.out.println(4 ...

  5. 描述java源程序构成_Java第二章Java程序设计

    <Java第二章Java程序设计>由会员分享,可在线阅读,更多相关<Java第二章Java程序设计(140页珍藏版)>请在人人文库网上搜索. 1.第2章 Java基本语法,2. ...

  6. 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 ...

  7. Java复习总结(二)Java SE 面试题

    Java SE基础知识 目录 Java SE 1. 请你谈谈Java中是如何支持正则表达式操作的? 2. 请你简单描述一下正则表达式及其用途. 3. 请你比较一下Java和JavaSciprt? 4. ...

  8. Java面试准备(一)——Java基础

    Java基础 一.基础概念与常识 1. Java和C++对比 2. Java语言有哪些特点 3. 什么是字节码?采用字节码的好处? 4. JVM,JRE和JDK 5. Oracle JDK和OpenJ ...

  9. 学习笔记(11):Java小白修炼手册-一句话在Java中如何表达?快学Java字符串

    立即学习:https://edu.csdn.net/course/play/27274/361060?utm_source=blogtoedu 1 JDK Java语言的开发包(开发使用) JRE J ...

最新文章

  1. 呼叫中心最难的问题是什么?
  2. tf.reduce_mean tf.reduce_sum优化目标函数时如何选择
  3. 算法(5) 归并排序
  4. ppct各代表什么_开关背面L、L1、L2各代表什么?火线,零线,地线怎样接?
  5. matlab安装_走进数模(三)MATLAB安装
  6. hihoCoder #1467 : 2-SAT·hihoCoder音乐节
  7. SAP Spartacus加载delivery region的实现
  8. python获取绝对路径的区别_python 获取路径不同方法的比较
  9. 在Google使用Borg进行大规模集群的管理 5-6
  10. 中事件源previous_PM2.5传感器在扬尘监测系统中的应用
  11. Ionic 开发环境搭建
  12. eclipse:STS下载使用(STS(Spring Tool Suite)其实是个被包装过的eclipse)
  13. 程序读取凡人修仙传热度数据
  14. Excel中截取特殊字符之前、之间、之后的数据
  15. pytorch中F.avg_pool1d()和F.avg_pool2d()
  16. 【数智化案例展】某头部股份制银行总行——“数字化投顾”工作台
  17. Android WallpaperManager 同时设置桌面壁纸与锁屏的问题
  18. (附源码)spring boot校园拼车微信小程序 毕业设计 091617
  19. 截图工具snipaste安装和使用
  20. 英伟达显卡笔记本如何免费获得2k甚至4k屏幕

热门文章

  1. c++11或c++14或c++17参数包的使用
  2. EntityFramework进阶——CodeFirst数据库迁移
  3. latex插入图片之后出现大段空白,并且紧随其后的文字如同被覆盖一般不见了
  4. java asynchronize_Java 中synchronize函数的实例详解
  5. 华硕主板专用Ghost Win11 64位专业体验版 V2021.08
  6. 微服务系列之ZooKeeper注册中心和Nacos注册中心Nacos和Zookeeper对比
  7. URL传Base64 造成报错 Illegal base64 character 20
  8. Java微服务篇4——Elastic search
  9. sqldataadapter.fill 索引超出了数组界限_小学生学习C++||第十五节 数组
  10. pythonsql注入步骤_防止SQL注入解决方案