BigDecimal adding wrong value

后端 未结 5 1967
谎友^
谎友^ 2020-11-27 08:15

I have a BigDecimal defined like this:

private static final BigDecimal sd = new BigDecimal(0.7d);

if i print it, i get the val

相关标签:
5条回答
  • 2020-11-27 08:44

    You should use the declared value in String literal such as new BigDecimal("0.7");

    0 讨论(0)
  • 2020-11-27 09:05

    Perhaps if you bothered to read the documentation, i.e. the javadoc of the constructor you're using, you'd already know the answer.

    1. When a double must be used as a source for a BigDecimal, note that this constructor provides an exact conversion; it does not give the same result as converting the double to a String using the Double.toString(double) method and then using the BigDecimal(String) constructor. To get that result, use the static valueOf(double) method.

    When you then look at the javadoc of BigDecimal.valueOf(double), you'll find:

    Note: This is generally the preferred way to convert a double (or float) into a BigDecimal, as the value returned is equal to that resulting from constructing a BigDecimal from the result of using Double.toString(double).

    So there is your answer: Use BigDecimal.valueOf(0.7d), not new BigDecimal(0.7d).

    0 讨论(0)
  • 2020-11-27 09:06

    Use a String literal:

    private static final BigDecimal sd = new BigDecimal("0.7");
    

    If you use a double, actually public BigDecimal(double val) is called. The reason you do not get 0.7 is that it cannot be exactly represented by a double. See the linked JavaDoc for more information.

    0 讨论(0)
  • 2020-11-27 09:08

    Constructing a BigDecimal from a double is surprisingly complicated. First, it can only be done via the detour of a string. (You can't get the constructor with double and a MathContext right. I've tried a lot. At the latest in cases in which the number of places before the decimal point would need to change due to rounding, it becomes difficult. Hence the warning in the Javadoc that you shouldn’t use it.)

    However, even there, it is not enough with a simple String.format(), since String.format() is sensitive to the default Locale and outputs different decimal separators depending on system/VM settings, while the BigDecimal constructor always requires a dot as a decimal separator. So you have to construct your own Formatter with Locale.US. If you have this up and running, you will get a warning of an unclosed resource.

    I found this to work:

    static BigDecimal toBigDecimal(double value, int decimalPlaces) {
        String format = "%." + decimalPlaces + "f";
        try (Formatter formatter = new Formatter(Locale.US)) {
            String formatted = formatter.format(format, value).toString();
            return new BigDecimal(formatted);
        }
    }
    
    0 讨论(0)
  • 2020-11-27 09:10

    Here are three ways:

    private static final BigDecimal sd = new BigDecimal("0.7");
    private static final BigDecimal sd = new BigDecimal(0.7d, MathContext.DECIMAL32);
    private static final BigDecimal sd = new BigDecimal(0.7d, MathContext.DECIMAL64)
    
    0 讨论(0)
提交回复
热议问题