java - 比较两个向下舍入到特定小数的双变量时是否存在精度问题?
问题描述
我正在尝试比较使用 BigDecimals 和 RoundingMode 向下舍入到特定小数位的两个双精度类型变量。
例如,当比较 3.1456 和 3.145(在 if 语句中舍入到小数点后 3 位)时,我的 if 语句只有在两个值彼此相等时才应该返回 true。
但是,它不适用于我的代码
BigDecimal one = new BigDecimal(3.1456).setScale(3, RoundingMode.DOWN);
BigDecimal two = new BigDecimal(3.145).setScale(3, RoundingMode.DOWN);
if (one.equals(two)) {
System.out.println("Both variables are equal");
} else {
System.out.println("Both variables are not equal");
}
输出逻辑为假。所以我做了一些检查,看看我的变量被四舍五入到的值。分别是 3.145 和 3.144,这是出乎意料的。找不到3.144的原因...
接下来,我通过使用 DecimalFormat 和 RoundingMode 使用另一种方法来完成上述操作。它工作得很好。
DecimalFormat df0 = new DecimalFormat("#.###");
DecimalFormat df1 = new DecimalFormat("#.###");
df0.setRoundingMode(RoundingMode.DOWN);
df1.setRoundingMode(RoundingMode.DOWN);
if (df0.format(num0).equals(df1.format(num1))) {
System.out.println("Both variables are equal")
} else {
System.out.println("Both variables are not equal")
}
上面的方法效果很好!BigDecimal 将这两个值都计算为 3.145。
与使用 DecimalFormat 相比,我无法理解为什么使用 BigDecimal 执行任务时它不起作用。与双类型变量的工作方式有关吗?像 (double)(0.2-0.1) 这样的结果是 0.09999999...而不是 0.1?
请给我一个更好的解决方案和理解!太感谢了!
解决方案
如文件所述,这BigDecimal(double)
是不可预测的:
此构造函数的结果可能有些不可预测。有人可能会假设用 Java 编写 new BigDecimal(0.1) 会创建一个正好等于 0.1 的 BigDecimal(未缩放的值 1,缩放为 1),但它实际上等于 0.10000000000000000555511151231257827021181583404541015625。这是因为 0.1 不能完全表示为双精度数(或者,就此而言,不能表示为任何有限长度的二进制分数)。因此,传递给构造函数的值并不完全等于 0.1,尽管看起来如此。
他们建议使用BigDecimal(String)
作为替代方案:
另一方面,String 构造函数是完全可预测的:编写 new BigDecimal("0.1") 会创建一个与 0.1 完全相等的 BigDecimal,正如人们所期望的那样。因此,一般建议优先使用 String 构造函数。
来自以下文档BigDecimal(String)
:
这通常是将 float 或 double 转换为 BigDecimal 的首选方法,因为它不会受到 BigDecimal(double) 构造函数的不可预测性的影响。
推荐阅读
- python - Python TypeError:不可散列的类型:scikit load_boston 数据上的“切片”
- django - 在两个数据库之间同步 postgres 表
- javascript - ES6 解构为“this”
- machine-learning - 我想检测图像中的枪支。给定背景中有这么多物体的图像,进行物体检测(对于枪)的正确步骤是什么?
- asp.net-core - 如何在我的 dot net core 项目中引用 lodash?
- java - HashMap的Node中存储hash的目的是什么?
- excel - 如何找到最大数据的行数并设置为0
- apache-kafka - 对同一个kafka主题产生一批事件相互覆盖
- php - PHP - 如何获取受保护的属性
- javascript - 如何从数组中打印数字?