jerry.pepper
jerry.pepper

Reputation: 185

BigDecimal/double Precision - number rounds up higher

The second of below method calls, to setYCoordinate(), gets incorrect value -89.99999435599995 instead of -89.99999435599994.

The first call to setXCoordinate() gets correct value 29.99993874900002.

setXCoordinate(BigDecimal.valueOf(29.99993874900002))
setYCoordinate(BigDecimal.valueOf(-89.99999435599994))

I put a breakpoint inside BigDecimal.valueOf() - this method's code looks as below -

public static BigDecimal valueOf(double val) {
        // Reminder: a zero double returns '0.0', so we cannot fastpath
        // to use the constant ZERO.  This might be important enough to
        // justify a factory approach, a cache, or a few private
        // constants, later.
        return new BigDecimal(Double.toString(val));
    }

The argument received by valueOf i.e. "double val" itself is -89.99999435599995 when inspected. Why? I have Java version set as below in my Maven pom.xml

<java.version>1.8</java.version>

Upvotes: 2

Views: 302

Answers (3)

Hulk
Hulk

Reputation: 6573

Your confusion has nothing to do with BigDecimal.

double d = -89.99999435599994;
System.out.println(d); //or inspecting it in a debugger

yields:

-89.99999435599995

This is just the way doubles work in java, in combination with the way Double.toString defines the String-representation. This conversion happens before any method is invoked, when the literal is interpreted as double. The details are specified in JLS Chapter 3.10.2. Floating-Point Literals and the JavaDocs of Double.valueOf(String).


If you need to express the value -89.99999435599994 as BigDecimal, the easiest way is to use the constructor taking a String, as other answers have already pointed out:

BigDecimal bd = new BigDecimal("-89.99999435599994");

BigDecimal bd = new BigDecimal("-89.99999435599994");
System.out.println(bd);

yields:

-89.99999435599994

Upvotes: 1

kshetline
kshetline

Reputation: 13682

You're right on the edge of precision for a double-precision floating point value, with 16 digits specified, and there's just shy of a full 16 digits of decimal accuracy available. If you skip BigDecimal entirely, just set a double to -89.99999435599994 and print it back out, you'll get -89.99999435599995.

Upvotes: 0

Jacob G.
Jacob G.

Reputation: 29680

Because a double can't retain that much precision; you shouldn't use a double, but rather a String when initializing your BigDecimal:

new BigDecimal("29.99993874900002");
new BigDecimal("-89.99999435599994");

See: Is floating point math broken?

Upvotes: 9

Related Questions