免费办公模板网站有哪些,wordpress 媒体管理,注册城乡规划师有用吗,微信公众号菜单跳转的网页怎么制作看下面这段代码#xff0c;将 d1 和 d2 两个浮点数进行比较#xff0c;输出的结果会是什么#xff1f;
double d1 .1 * 3;
double d2 .3;
System.out.println(d1 d2);按照正常逻辑来看#xff0c;d1 经过计算之后的结果应该是 0.3#xff0c;最后打印的结果应该是 tru…看下面这段代码将 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 标准就会有精度的问题。
存储和转换的过程中浮点数容易引起一些较小的舍入误差正是这个原因导致在比较浮点数的时候不能使用“”操作符——要求严格意义上的完全相等。
那么如何正确的比较浮点数呢这里有两种方案。
方案1比较绝对值误差
第一种方案是允许两个值之间存在一点误差指定一个阈值使用 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 相等。
方案2BigDecimal
第二种方案是使用 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 inflationlong 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 differlong 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;elsereturn 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
0d1 和 d2 都为 0.3所以 compareTo() 的结果就为 0表示两个值是相等的。
总结一下在遇到浮点数的时候千万不要使用 操作符来进行比较因为有精度问题。要么使用阈值来忽略舍入的问题要么使用 BigDecimal 来替代 double 或者 float。