简体   繁体   English

RoundingMode.HALF_UP中的结果不同

[英]Different result in RoundingMode.HALF_UP

Please comment me freely. 请自由评论我。 What was wrong in the following program. 以下程序出了什么问题。 It is giving different round result. 它给出了不同的圆形结果。

public class Test {
    public static String round(double value, int places) {
        BigDecimal bd = new BigDecimal(value);
        bd = bd.setScale(places, RoundingMode.HALF_UP);
        return bd.toPlainString();
    }

    public static void main(String[] args) throws Exception {
        double value1 = 1.1234565;
        System.out.println(round(value1, 6));
        double value2 = 1.1235;
        System.out.println(round(value2, 3));
    }
}

Why it is out put like that? 为什么这样出来?

1.123457
1.123   --> Actually, I expect 1.124

In Doc(eclipse) 在Doc(eclipse)

在此输入图像描述

You're calling the BigDecimal(double) constructor. 你正在调用BigDecimal(double)构造函数。 That's documented as: 这记录为:

Translates a double into a BigDecimal which is the exact decimal representation of the double's binary floating-point value. 将double转换为BigDecimal,它是double的二进制浮点值的精确十进制表示形式。 The scale of the returned BigDecimal is the smallest value such that (10scale × val) is an integer. 返回的BigDecimal的比例是最小值,使得(10scale×val)是整数。

The notes are illuminating too, and I suggest you read them. 这些笔记也很有启发性,我建议你阅读它们。

The value you're passing in is exactly 1.12349999999999994315658113919198513031005859375, as that's the closest double to 1.1235. 您正在传递的价值是完全1.12349999999999994315658113919198513031005859375,因为这是最接近的double至1.1235。 You can see that if you print out bd.toPlainString() before calling setScale . 如果在调用setScale之前打印出bd.toPlainString() ,则可以看到。 Therefore, that isn't half-way between 1.123 and 1.124 - it's closest to 1.123. 因此,这不是 1.123和1.124之间的中间 - 它最接近1.123。

If you want a BigDecimal value of exactly 1.1235, I suggest you pass it as a String instead: 如果你想要BigDecimal恰好是 1.1235,我建议你把它作为String传递:

import java.math.*;

public class Test {
    public static String round(String value, int places) {
        BigDecimal bd = new BigDecimal(value);
        bd = bd.setScale(places, RoundingMode.HALF_UP);
        return bd.toPlainString();
    }

    public static void main(String[] args) throws Exception {
        String value1 = "1.1234565";
        System.out.println(round(value1, 6));
        String value2 = "1.1235";
        System.out.println(round(value2, 3));
    }
}

Alternatively you could use BigDecimal.valueOf(double) instead of new BigDecimal(double) - but then you still have the problem that you've converted your real original source data (the text in your source code) into a binary floating point number first, potentially losing information. 或者你可以使用BigDecimal.valueOf(double)而不是new BigDecimal(double) - 但是你仍然遇到的问题是你已经将真正的原始源数据(源代码中的文本)转换为二进制浮点数,可能会丢失信息。

The problem is you are using to exact represention of the double including any representation error. 问题是你正在使用精确的double表示,包括任何表示错误。 A simple solution is to use the value you would get from the double if it was printed. 一个简单的解决方案是使用打印时从double获得的值。

public static String round(double value, int places) {
    return BigDecimal.valueOf(value)
                     .setScale(places, RoundingMode.HALF_UP);
                     .toPlainString();
}

BigDecimal.valueOf uses the simplest value which would be represented as the double you have. BigDecimal.valueOf使用最简单的值,该值将表示为您拥有的double BigDecimal.valueOf值。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM