java - 使用 DecimalFormat 的 RoundingMode.UP 无法按预期工作
问题描述
每当有十进制值时,我都会尝试将 Double 数字四舍五入。我正在尝试以下。下面的代码片段按预期四舍五入所有其他值。
1.08 -> 2
9.5 -> 10
但将 0.08 舍入为 0 而不是 1。我在这里遗漏了什么吗?
DecimalFormat df = new DecimalFormat("0");
df.setRoundingMode(RoundingMode.UP);
Double number = 0.08;
System.out.println(df.format(number)); // expecting 1 but produces 0
number = 1.08;
System.out.println(df.format(number)); // correctly produces 2
解决方案
这看起来像是针对 JDK8 报告的错误 JDK-8174722的表现,并且仍然以修复版本“tbd”打开(我在 JDK14 上看到了相同的行为)。在该错误报告中,错误地四舍五入0.0001
到小数点后两位会导致0.00
而不是0.01
.
我试图通过源代码来跟踪这个计算,DecimalFormat
并发现了对有效数字的多个假设,为了兼容性而保留,但显然是导致此类问题的原因。我基于源代码的预感是,如果请求精度之后的第一个数字为 0(或足够接近),则函数会向下舍入。这种行为与明确说明的文档相反。
如果它很容易修复,我认为链接的错误早就被修复了,但它似乎也是一个低优先级。
正如评论所建议的那样,使用Math.ceil()
、Math.floor()
和Math.round()
函数将提供更可预测/一致的结果,并且足以满足大多数用例。
在您的评论中,您建议用户RoundingMode
提供. @Andreas在此评论中发布了此解决方法的应用程序以生成此字符串:BigDecimal.setScale()
// Note: this ignores Locale
BigDecimal.valueOf(number).setScale(0, RoundingMode.UP).toPlainString();
使用 a 的另一个选项DecimalFormat
将允许更改区域设置,并且是:
df.format(BigDecimal.valueOf(number).setScale(0, RoundingMode.UP));
请注意,由于您将使用四舍五入,因此setScale()
您不需要在DecimalFormat
.
推荐阅读
- c# - 解决接口的多重实现
- informix - ifxnjs 不支持 NODE_MODULE_VERSION 64
- tfs - 给出“MsBuild.exe”的 SonarScanner 在 TFS 2018 上未被识别为内部或外部命令
- java - Hazelcast-wm 节点如何在 P2P 模式下找到彼此?
- java - 将多个文件添加到 Spring mime 消息时出错
- python - 将 tensorflow 导入为 tf 时导入 TensorFlow 时出错
- prolog - 对原子的子类进行分类的序言错误
- server - https://dnsflagday.net/ 报告 edns512tcp=timeout
- javascript - Javascript innerHTML 转换为表单文本值
- python - Displaying the escaped version of a string in python