Categories
askquestion

“new BigDecimal(13.3D)” results in imprecise “13.3000000000000007105..”?

“new BigDecimal(13.3D)” results in imprecise “13.3000000000000007105..”?

Ask Question

Asked
11 years ago

Active
7 years, 9 months ago

Viewed
5k times

.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty{
margin-bottom:0;
}

16

6

How is it that Java’s BigDecimal can be this painful?

Double d = 13.3D;

BigDecimal bd1 = new BigDecimal(d);
BigDecimal bd2 = new BigDecimal(String.valueOf(d));

System.out.println(“RESULT 1: “+bd1.toString());
System.out.println(“RESULT 2: “+bd2.toString());

RESULT 1: 13.300000000000000710542735760100185871124267578125
RESULT 2: 13.3

Is there any situation where Result 1 would be desired? I know that Java 1.5 changed the toString() method but was this the intended consequence?

Also I realise that BigDecimal has doubleValue() etc, but the library that I am working with helpfully uses a toString() and I can’t change that 🙁

Cheers.

java precision bigdecimal

share|improve this question

edited May 15 ’12 at 15:19

user166390

asked Jan 20 ’09 at 10:36

DamoDamo

10.7k55 gold badges5050 silver badges7171 bronze badges

1

Actually the toString() version is probably what you want. Decimal numbers cannot be properly represented as a double, and while BigDecimals solve this problem, giving them a double in the constructor undermines the solution as they do not have an accurate number to start from.

– Andrzej Doyle
Jan 20 ’09 at 11:04

add a comment
 | 

5 Answers
5

active

oldest

votes

50

Well, the API does address this apparent inconsistency in the constructor BigDecimal(double val):

The results of this constructor can be somewhat unpredictable. One might
assume that writing new
BigDecimal(0.1) in Java creates a
BigDecimal which is exactly equal to
0.1 (an unscaled value of 1, with a scale of 1), but it is actually equal
to
0.1000000000000000055511151231257827021181583404541015625. This is because 0.1 cannot be
represented exactly as a double (or,
for that matter, as a binary fraction
of any finite length). Thus, the value
that is being passed in to the
constructor is not exactly equal to
0.1, appearances notwithstanding.
The String constructor, on the other hand, is perfectly predictable:
writing new BigDecimal(“0.1″) creates
a BigDecimal which is exactly equal to
0.1, as one would expect. Therefore, it is generally recommended that the
String constructor be used in
preference to this one.
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.

Moral of the story: The pain seems self-inflicted, just use new BigDecimal(String val) or BigDecimal.valueOf(double val) instead =)

share|improve this answer

edited Jan 20 ’09 at 11:03

answered Jan 20 ’09 at 10:50

Zach ScrivenaZach Scrivena

26k1010 gold badges5757 silver badges6969 bronze badges

5

+1: That’s how Double really works. Not much to do with BigDecimal.

– S.Lott
Jan 20 ’09 at 11:03

Nice one. So really someone should throw a RTFM at me 😉

– Damo
Jan 20 ’09 at 11:43

Note that also new BigDecimal(d+””) works fine. Results in “13.3” just like when using valueOf(d)

– BAERUS
May 28 ’15 at 12:27

add a comment
 | 

11

Your problem has nothing to do with BigDecimal, and everything with Double, which cannot represent 13.3 accurately, since it uses binary fractions internally.

So your error is introduced in the very first line. The first BigDecimal simply preserves it, while String.valueOf() does some fishy rounding that causes the second one to have the desired content, pretty much through luck.

share|improve this answer

edited Dec 14 ’11 at 21:23

Bhesh Gurung

45.8k2020 gold badges8383 silver badges135135 bronze badges

answered Jan 20 ’09 at 10:40

Michael BorgwardtMichael Borgwardt

312k7171 gold badges448448 silver badges680680 bronze badges

add a comment
 | 

8

You might want to inform yourself about how floating-point values are implemented (IEEE 754-1985). And suddenly, everything will become crystal-clear.

share|improve this answer

answered Jan 20 ’09 at 10:39

BombeBombe

69.3k2020 gold badges110110 silver badges120120 bronze badges

add a comment
 | 

5

This isn’t the fault of BigDecimal – it’s the fault of double. BigDecimal is accurately representing the exact value of d. String.valueOf is only showing the result to a few decimal places.

share|improve this answer

edited Dec 14 ’11 at 21:24

Bhesh Gurung

45.8k2020 gold badges8383 silver badges135135 bronze badges

answered Jan 20 ’09 at 10:38

Jon SkeetJon Skeet

1163k741741 gold badges83578357 silver badges86968696 bronze badges

add a comment
 | 

3

Fractions represented with binary number types(i.e. double, float) cannot be accurately stored in those types.

Double d = 13.3;
BigDecimal bdNotOk = new BigDecimal(d);
System.out.println(“not ok: ” + bdNotOk.toString());

BigDecimal bdNotOk2 = new BigDecimal(13.3);
System.out.println(“not ok2: ” + bdNotOk2.toString());

double x = 13.3;
BigDecimal ok = BigDecimal.valueOf(x);
System.out.println(“ok: ” + ok.toString());

double y = 13.3;
// pretty lame, constructor’s behavior is different from valueOf static method
BigDecimal bdNotOk3 = new BigDecimal(y);
System.out.println(“not ok3: ” + bdNotOk3.toString());

BigDecimal ok2 = new BigDecimal(“13.3”);
System.out.println(“ok2: ” + ok2.toString());

Double e = 0.0;
for(int i = 0; i < 10; ++i) e = e + 0.1; // some fractions cannot be accurately represented with binary
System.out.println(“not ok4: ” + e.toString()); // should be 1

BigDecimal notOk5 = BigDecimal.valueOf(e);
System.out.println(“not ok5: ” + notOk5.toString()); // should be 1

/*
* here are some fractions that can be represented exactly in binary:
* 0.5 = 0.1 = 1 / 2
* 0.25 = 0.01 = 1 / 4
* 0.75 = 0.11 = 3 / 4
* 0.125 = 0.001 = 1 / 8
*/

output:

not ok: 13.300000000000000710542735760100185871124267578125
not ok2: 13.300000000000000710542735760100185871124267578125
ok: 13.3
not ok3: 13.300000000000000710542735760100185871124267578125
ok2: 13.3
not ok4: 0.9999999999999999
not ok5: 0.9999999999999999

Just use BigDecimal.valueOf(d) or new BigDecimal(s).

share|improve this answer

edited Dec 14 ’11 at 21:24

Bhesh Gurung

45.8k2020 gold badges8383 silver badges135135 bronze badges

answered Jan 20 ’09 at 11:21

Michael BuenMichael Buen

34.2k66 gold badges8282 silver badges108108 bronze badges

add a comment
 | 

Your Answer

Thanks for contributing an answer to Stack Overflow!Please be sure to answer the question. Provide details and share your research!But avoid …Asking for help, clarification, or responding to other answers.Making statements based on opinion; back them up with references or personal experience.To learn more, see our tips on writing great answers.

Draft saved
Draft discarded

Sign up or log in

Sign up using Google

Sign up using Facebook

Sign up using Email and Password

Submit

Post as a guest

Name

Email
Required, but never shown

Post Your Answer

Discard

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you’re looking for? Browse other questions tagged java precision bigdecimal or ask your own question.

Blog

When laziness is efficient: Make the most of your command line

Ben Popper is the worst coder in the world: Something awry with my array

Featured on Meta

TLS 1.0 and TLS 1.1 removal for Stack Exchange services

Did Stack Exchange cut the number of negative comments nearly in half between…

An account of my meeting with the Stack Overflow management team

Linked

2

How to get exact decimal value from bigdecimal in java

3

Fastest way to instantiate BigDecimal from string

1

Rounding a Double to 2dp

0

How to divide a BigDecimal and get the same value after sum these values

Related

151Addition for BigDecimal286Double vs. BigDecimal?133BigDecimal setScale and round230Compare if BigDecimal is greater than zero493ArithmeticException: “Non-terminating decimal expansion; no exact representable decimal result”6720Why is subtracting these two times (in 1927) giving a strange result?90BigDecimal – to use new or valueOf196How to check if BigDecimal variable == 0 in java?202Rounding BigDecimal to *always* have two decimal places

Hot Network Questions

Busiest domestic-only airport?

How does the file command distinguish text and LaTeX files?

Unix Haters Handbook – guaranteeing synchronous, atomic operations

Result object vs throwing exceptions

What happens if you can’t pay at an auction?

Could New Horizons take a “Pale Blue Dot”-like image this year?

Did Lucille Ball have a creative influence on Star Trek?

7zip : Why does encrypting the same file with AES-256 not give the same output?

What’s the difference between ‘hier(7)’ and ‘file-hierarchy(7)’ man pages?

Using two tires on one wheel to prevent punctures?

Would allowing the Rogue sub-class (Assassin) to benefit from Supreme Sneak be unbalanced?

What is the Dorfman method in chess?

Is it unethical for a professor to misrepresent the format of an exam?

What exactly is ALF?

How should the ESTA question “Have you ever been issued a passport or ID for travel by any other country?” be understood?

What should I (a professor) do if a student keeps answering other students’ questions before I start explaining?

Crooked (Not Parallel with Wall) Electrical Receptacle

PhD manuscript with grammatical errors and informal phrases

How could hackers cause mass destruction to major cities using existing satellites?

How to convert graphical images to ASCII art?

Player has trouble imagining the ingame situation

Is this a game to you?

Removing a nested list associated with a key and inserting into a new list

I have a 2nd broken spoke after 300km on a new bike, is it the wheel or me?

more hot questions

Question feed

Subscribe to RSS

Question feed
To subscribe to this RSS feed, copy and paste this URL into your RSS reader.

lang-java

Leave a Reply

Your email address will not be published. Required fields are marked *