openjdk8中的舍入问题
Posted
技术标签:
【中文标题】openjdk8中的舍入问题【英文标题】:Rounding issue in openjdk8 【发布时间】:2019-10-15 12:48:12 【问题描述】:我在 open jdk1.8 中使用 NumberFormat.format(double)
时遇到了一些奇怪的问题。 我知道在此版本中修复了之前版本中的舍入问题,但仍然似乎有些不对劲。
public static void main (String args[])
double num = 16.34625;
NumberFormat nf = NumberFormat.getInstance();
nf.setGroupingUsed(false);
nf.setMinimumFractionDigits(2);
nf.setMaximumFractionDigits(4);
System.out.println("nf : " + nf.getRoundingMode());
System.out.println("BigDecimal is " + new BigDecimal(num).toString());
System.out.println("num after number format : " + nf.format(num));
这是显示的实际结果:
nf : HALF_EVEN
num : 16.34625
BigDecimal is 16.346250000000001278976924368180334568023681640625
num after number format : 16.3463
但是,我希望它被四舍五入到 16.3462,因为在 HALF_EVEN 模式下,被丢弃的数字左边的数字是偶数,所以它应该充当 HALF_DOWN。
这是支持此操作的 java 文档 (https://docs.oracle.com/javase/7/docs/api/java/math/RoundingMode.html#HALF_EVEN)。
【问题讨论】:
使用 HALF_EVEN 舍入时,它会舍入到最近的偶数 如果它与两个邻居的距离相等。但是 16.346250000000001278976924368180334568023681640625 比 16.3462 更接近 16.3463。你有一个事实,浮点数和双精度数不能准确地表示十进制数,这要感谢。尝试从您的数字的字符串表示形式(即“16.34625”)创建 BigDecimal 以获得所需的行为。 只需将double num = 16.34625;
替换为String num = "16.34625";
,看看会发生什么……
对不起,我还是有点困惑。我同意双 16.34625 的最接近表示是 16.346250000000001278976924368180334568023681640625。但是,由于小数点后的第5位是等距的'5',那么由于它的前一位是偶数的'4',它应该充当half_down,最终结果应该是16.3462。如果前面的数字是奇数,那么它应该作为 half_up。不对吗?
【参考方案1】:
您可以尝试在BigInteger
本身中四舍五入。您可以使用该类的setScale
方法。
System.out.println(new BigDecimal(num).setScale(4,BigDecimal.ROUND_HALF_EVEN));
//16.3463
【讨论】:
我不希望得到某个数字的四舍五入。我只是想知道为什么会出现这种行为。【参考方案2】:你说的都是对的。唯一的问题是,您的 BigDecimal 不是 16.34625,而是 16.346250000000001278976924368180334568023681640625。所以邻居不是等距的。
【讨论】:
以上是关于openjdk8中的舍入问题的主要内容,如果未能解决你的问题,请参考以下文章