I have seen a very weird behaviour in Java's double variable, as I'm trying to simply add small fractions to a double and I see a completely bizarre results.
double test = 0;
test += 0.71;
test += 0.2;
Now I'd expect the result to be:
test = 0.91
Right? Wrong!
In reality, this is the number I get in my test double:
test = 0.9099999999999999
Now while this is very close, it's a very bizarre fraction loss, and in the long run it causes serious bugs in my program.
With a float I've gotten even a weirder result.
Any help would be greatly appreciated.
Thanks
There is nothing bizarre about it at all. 0.91, 0.71 and 0.2 are not representable as a IEEE754 floating point values as they would have a recurring fractional part when represented in binary. The situation is entirely analogous to trying to represent 1/3 in base 10 with a finite number of digits. You can't do it.
What you are seeing is a rounding error that is normal when doing floating point calculations. You have to code around it. So for instance, you can't reliably compare for equality, you have to see the two numbers are within some small delta of each other. For a slightly more in depth but still understandable explanation see The Floating Point Guide.
That's the magic of binary encoding of floating point values (look for IEEE754 : http://en.wikipedia.org/wiki/IEEE_754-2008 ). If you want to be sure to never have this kind of things, you're maybe looking for BigDecimal :
http://docs.oracle.com/javase/1.5.0/docs/api/java/math/BigDecimal.html
Basic rules :
don't use equality tests when dealing with floating point numbers (you must test gaps)
round numbers you're displaying (usually using DecimalFormat)
don't use floating point numbers for financial applications
the float is generally the way to go for scientific or industrial operations, as long as you understand IEEE754
double can only approximate most fractional values. This means you need to use some rounding if you want to get your expect result. Or you can use BigDecimal which takes care of this issue for you.
double test = 0;
test += 0.71;
test += 0.2;
System.out.printf("%.2f%n", test);
prints
0.91
For your own interest
System.out.println("0.71 is actually " + new BigDecimal(0.71));
System.out.println("0.2 is actually " + new BigDecimal(0.2));
System.out.println("0.71+0.2 is actually " + new BigDecimal(0.71 + 0.2));
System.out.println("0.91 is actually " + new BigDecimal(0.91));
System.out.println("0.71+0.2 == 0.91 is " + (0.71 + 0.2 == 0.91));
prints
0.71 is actually 0.70999999999999996447286321199499070644378662109375
0.2 is actually 0.200000000000000011102230246251565404236316680908203125
0.71+0.2 is actually 0.9099999999999999200639422269887290894985198974609375
0.91 is actually 0.91000000000000003108624468950438313186168670654296875
0.71+0.2 == 0.91 is false
Java uses something called floating-point to represent decimals. They use exponential notation. Here's what I mean:
There is a multiplier (M), and an exponent between 1023 and -1022 (E).
A number (N) is represented like this: M * 2^E.
4.25 is represented like this:
17 * 2^-2.
0.91 cannot be represented in base 2 exactly, but Java can get pretty close:
0.909999999999..
Therefore, it is impossible to accurately add these numbers together.
Related
I know the following behavior is an old problem, but still I don't understand.
System.out.println(0.1 + 0.1 + 0.1);
Or even though I use BigDecimal
System.out.println(new BigDecimal(0.1).doubleValue()
+ new BigDecimal(0.1).doubleValue()
+ new BigDecimal(0.1).doubleValue());
Why this result is: 0.30000000000000004 instead of: 0.3?
How can I solve this?
What you actually want is
new BigDecimal("0.1")
.add(new BigDecimal("0.1"))
.add(new BigDecimal("0.1"));
The new BigDecimal(double) constructor gets all the imprecision of the double, so by the time you've said 0.1, you've already introduced the rounding error. Using the String constructor avoids the rounding error associated with going via the double.
First never, never use the double constructor of BigDecimal. It may be the right thing in a few situations but mostly it isn't
If you can control your input use the BigDecimal String constructor as was already proposed. That way you get exactly what you want. If you already have a double (can happen after all), don't use the double constructor but instead the static valueOf method. That has the nice advantage that we get the cannonical representation of the double which mitigates the problem at least.. and the result is usually much more intuitive.
This is not a problem of Java, but rather a problem of computers generally. The core problem lies in the conversion from decimal format (human format) to binary format (computer format). Some numbers in decimal format are not representable in binary format without infinite repeating decimals.
For example, 0.3 decimal is 0.01001100... binary But a computer has a limited "slots" (bits) to save a number, so it cannot save all the whole infinite representation. It saves only
0.01001100110011001100 (for example). But that number in decimal is no longer 0.3, but 0.30000000000000004 instead.
Try this:
BigDecimal sum = new BigDecimal(0.1).add(new BigDecimal(0.1)).add(new BigDecimal(0.1));
EDIT: Actually, looking over the Javadoc, this will have the same problem as the original. The constructor BigDecimal(double) will make a BigDecimal corresponding to the exact floating-point representation of 0.1, which is not exactly equal to 0.1.
This, however, gives the exact result, since integers CAN always be expressed exactly in floating-point representation:
BigDecimal one = new BigDecimal(1);
BigDecimal oneTenth = one.divide(new BigDecimal(10));
BigDecimal sum = oneTenth.add(oneTenth).add(oneTenth);
The problem you have is that 0.1 is represented with a slightly higher number e.g.
System.out.println(new BigDecimal(0.1));
prints
0.1000000000000000055511151231257827021181583404541015625
The Double.toString() takes into account this representation error so you don't see it.
Similarly 0.3 is represented by a value slightly lower than it really is.
0.299999999999999988897769753748434595763683319091796875
If you multiply the represented value of 0.1 by 3 you don't get the represented value for 0.3, you instead get something a little higher
0.3000000000000000166533453693773481063544750213623046875
This is not just a representation error but also a rounding error caused by the operations. This is more than the Double.toString() will correct and so you see the rounding error.
The moral of the story, if you use float or double also round the solution appropriately.
double d = 0.1 + 0.1 + 0.1;
System.out.println(d);
double d2 = (long)(d * 1e6 + 0.5) / 1e6; // round to 6 decimal places.
System.out.println(d2);
prints
0.30000000000000004
0.3
Is this a glitch in Java?
I go to solve this expression: 3.1 - 7.1
I get the answer: -3.9999999999999996
What is going on here?
A great explanation can be found here. http://www.ibm.com/developerworks/java/library/j-jtp0114/
Floating point arithmetic is rarely exact. While some numbers, such
as 0.5, can be exactly represented as a binary (base 2) decimal (since
0.5 equals 2-1), other numbers, such as 0.1, cannot be. As a result, floating point operations may result in rounding errors, yielding a
result that is close to -- but not equal to -- the result you might
expect. For example, the simple calculation below results in
2.600000000000001, rather than 2.6:
double s=0;
for (int i=0; i<26; i++)
s += 0.1;
System.out.println(s);
Similarly, multiplying .1*26 yields a result different from that of
adding .1 to itself 26 times. Rounding errors become even more serious
when casting from floating point to integer, because casting to an
integral type discards the non-integral portion, even for calculations
that "look like" they should have integral values. For example, the
following statements:
double d = 29.0 * 0.01;
System.out.println(d);
System.out.println((int) (d * 100));
will produce as output:
0.29
28
which is probably not what you might expect at first.
See the provided reference for more information.
As mentioned by several others you cannot count on double if you would like to get an exact decimal value, e.g. when implementing monetary applications. What you should do instead is to take a closer look at BigDecimal:
BigDecimal a = new BigDecimal("3.1");
BigDecimal b = new BigDecimal("7.1");
BigDecimal result = a.subtract(b);
System.out.println(result); // Prints -4.0
Computers are 100% so in the math world that is correct, to the average person it is not. Java cant have a error on a specific number as it is just code that runs the same way but has a different input!
P.S. Google how to round a number
rounding errors in floating points
same way that 3 * 0.1 != 0.3 (when it's not folded by the compiler at least)
Automatic type promotion is happening and that is the result.
Here is some resource to learn.
http://docs.oracle.com/javase/specs/jls/se5.0/html/conversions.html
The next step would be is to learn to use formatters to format it to the given precision / requirements.
double x = 1;
double y = 3 * (1.0 / 3);
x == y
In a powerpoint I am studying, it said the statement is logically questionable. I cannot find out why it is thus, I mean you use == for primitives correct, or is it Logically questionable because doubles are not stored exactly or am I missing something obvious? Thanks
I think you've got it: since the data types are doubles, rather than int or Integer, the resulting x and y may not be precisely equal.
It is logically questionable because the compare statement at the end would evaluate to false. Doubles are stored as a series of powers of two. So values like 1/2 and 1/4 and 1/8 could actually be expressed in floating point formats exactly, but not 1/3. It will be approximated to 1/4 + 1/64 + ... there is now way it could exactly be apprroximate 1/3
Correct way to compare the floats is like this:
Math.double.abs ( x - y ) > tol
where tol is set to something sufficiently small, depending on your application. For example most graphics applications work well with tol = 0.00001
Because 1.0 / 3 is 0.3333..., up to the capacity of a double. 3 * 0.3333... is 0.9999..., up to the capacity of a double.
So we have the question 1 == 0.9999..., which I guess you could call "logically questionable".
It's because of roundoff error. The problem is analogous to the precision problems you have have with decimals when dealing with numbers that cannot be precisely expressed in the format you are using.
For example, with six digits of decimal precision, the best you can do for 1/3 is .333333. But:
1/3 + 1/3 + 1/3 -> .33333 + .333333 + .33333 = .999999 != 1.000000
Ouch. For 2/3, you can use either .666666 or .666667 but either way, you have problems.
If 2/3 -> .666666 then:
2/3 + 1/3 -> .333333 + .666666 != 1.000000
Ouch.
And if 2/3. -> .666667 then:
1/3 * 2 - 2/3 -> .333333 * 2.00000 - .666667 = .666666 - .666667 != 0
Ouch.
It's analogous with doubles. This paper is considered the authoritative work on the subject. In simple terms -- never compare floating point numbers for equality unless you know exactly what you're doing.
Logically questionable because doubles are not stored exactly
More or less.
As a general rule, a double cannot represent the precise value of a Real number. The value 1/3 is an example.
Some numbers can be represented precisely as double values. 1.0 and 3.0 are examples. However, the division operator produces a number (in this case) that cannot be represented.
In general, any code that uses == to compare double or float values is questionable ... in the sense that you need to analyse each case carefully to know whether the use of == is correct. (And the analysis is not intuitive for people who were taught at a very early age to do arithmetic in base 10!)
From the software engineering standpoint, the fact that you need to do a case-by-case analysis of == usage makes it questionable practice. Good software engineering is (in part) about eliminating mistakes and sources of mistakes.
In my JAVA program there is code like this:
int f_part = (int) ((f_num - num) * 100);
f_num is double and num is long. I just want to take the fractional part out and assign it to f_part. But some times f_part value is one less than it's value. Which means if f_num = 123.55 and num = 123, But f_part equals to 54. And it happens only f_num and num is greater than 100. I don't know why this happening. Please can someone explain why this happens and way to correct it.
This is due to the limited precision in doubles.
The root of your problem is that the literal 123.55 actually represents the value 123.54999....
It may seem like it holds the value 123.55 if you print it:
System.out.println(123.55); // prints 123.55
but in fact, the printed value is an approximation. This can be revealed by creating a BigDecimal out of it, (which provides arbitrary precision) and print the BigDecimal:
System.out.println(new BigDecimal(123.55)); // prints 123.54999999999999715...
You can solve it by going via Math.round but you would have to know how many decimals the source double actually entails, or you could choose to go through the string representation of the double in fact goes through a fairly intricate algorithm.
If you're working with currencies, I strongly suggest you either
Let prices etc be represented by BigDecimal which allows you to store numbers as 0.1 accurately, or
Let an int store the number of cents (as opposed to having a double store the number of dollars).
Both ways are perfectly acceptable and used in practice.
From The Floating-Point Guide:
internally, computers use a format (binary floating-point) that cannot
accurately represent a number like 0.1, 0.2 or 0.3 at all.
When the code is compiled or interpreted, your “0.1” is already
rounded to the nearest number in that format, which results in a small
rounding error even before the calculation happens.
It looks like you're calculating money values. double is a completely inappropriate format for this. Use BigDecimal instead.
int f_part = (int) Math.round(((f_num - num) * 100));
This is one of the most often asked (and answered) questions. Floating point arithmetics can not produce exact results, because it's impossible to have an inifinity of real numbers inside 64 bits. Use BigDecimal if you need arbitrary precision.
Floating point arithmetic is not as simple as it may seem and there can be precision issues.
See Why can't decimal numbers be represented exactly in binary?, What Every Computer Scientist Should Know About Floating-Point Arithmetic for details.
If you need absolutely sure precision, you might want to use BigDecimal.
This question already has answers here:
Double vs. BigDecimal?
(7 answers)
Closed 7 years ago.
When dealing with real world monetary values, I am advised to use BigDecimal instead of Double.But I have not got a convincing explanation except, "It is normally done that way".
Can you please throw light on this question?
I think this describes solution to your problem: Java Traps: Big Decimal and the problem with double here
From the original blog which appears to be down now.
Java Traps: double
Many traps lay before the apprentice programmer as he walks the path of software development. This article illustrates, through a series of practical examples, the main traps of using Java's simple types double and float. Note, however, that to fully embrace precision in numerical calculations you a text book (or two) on the topic is required. Consequently, we can only scratch the surface of the topic. That being said, the knowledge conveyed here, should give you the fundamental knowledge required to spot or identify bugs in your code. It is knowledge I think any professional software developer should be aware of.
Decimal numbers are approximations
While all natural numbers between 0 - 255 can be precisely described using 8 bit, describing all real numbers between 0.0 - 255.0 requires an infinitely number of bits. Firstly, there exists infinitely many numbers to describe in that range (even in the range 0.0 - 0.1), and secondly, certain irrational numbers cannot be described numerically at all. For example e and π. In other words, the numbers 2 and 0.2 are vastly differently represented in the computer.
Integers are represented by bits representing values 2n where n is the position of the bit. Thus the value 6 is represented as 23 * 0 + 22 * 1 + 21 * 1 + 20 * 0 corresponding to the bit sequence 0110. Decimals, on the other hand, are described by bits representing 2-n, that is the fractions 1/2, 1/4, 1/8,... The number 0.75 corresponds to 2-1 * 1 + 2-2 * 1 + 2-3 * 0 + 2-4 * 0 yielding the bits sequence 1100 (1/2 + 1/4).
Equipped with this knowledge, we can formulate the following rule of thumb: Any decimal number is represented by an approximated value.
Let us investigate the practical consequences of this by performing a series of trivial multiplications.
System.out.println( 0.2 + 0.2 + 0.2 + 0.2 + 0.2 );
1.0
1.0 is printed. While this is indeed correct, it may give us a false sense of security. Coincidentally, 0.2 is one of the few values Java is able to represent correctly. Let's challenge Java again with another trivial arithmetical problem, adding the number 0.1 ten times.
System.out.println( 0.1f + 0.1f + 0.1f + 0.1f + 0.1f + 0.1f + 0.1f + 0.1f + 0.1f + 0.1f );
System.out.println( 0.1d + 0.1d + 0.1d + 0.1d + 0.1d + 0.1d + 0.1d + 0.1d + 0.1d + 0.1d );
1.0000001
0.9999999999999999
According to slides from Joseph D. Darcy's blog the sums of the two calculations are 0.100000001490116119384765625 and 0.1000000000000000055511151231... respectively. These results are correct for a limited set of digits. float's have a precision of 8 leading digits, while double has 17 leading digits precision. Now, if the conceptual mismatch between the expected result 1.0 and the results printed on the screens were not enough to get your alarm bells going, then notice how the numbers from mr. Darcy's slides does not seem to correspond to the printed numbers! That's another trap. More on this further down.
Having been made aware of mis-calculations in seemingly the simples possible scenarios, it is reasonable to contemplate on just how quickly the impression may kick in. Let us simplify the problem to adding only three numbers.
System.out.println( 0.3 == 0.1d + 0.1d + 0.1d );
false
Shockingly, the imprecision already kicks in at three additions!
Doubles overflow
As with any other simple type in Java, a double is represented by a finite set of bits. Consequently, adding a value or multiplying a double can yield surprising results. Admitedly, numbers have to be pretty big in order to overflow, but it happens. Let's try multiplying and then dividing a big number. Mathematical intuition says that the result is the original number. In Java we may get a different result.
double big = 1.0e307 * 2000 / 2000;
System.out.println( big == 1.0e307 );
false
The problem here is that big is first multiplied, overflowing, and then the overflowed number is divided. Worse, no exception or other kinds of warnings are raised to the programmer. Basically, this renders the expression x * y completely unreliable as no indication or guarantee is made in the general case for all double values represented by x, y.
Large and small are not friends!
Laurel and Hardy were often disagreeing about a lot of things. Similarly in computing, large and small are not friends. A consequence of using a fixed number of bits to represent numbers is that operating on really large and really small numbers in the same calculations will not work as expected. Let's try adding something small to something large.
System.out.println( 1234.0d + 1.0e-13d == 1234.0d );
true
The addition has no effect! This contradicts any (sane) mathematical intuition of addition, which says that given two numbers positive numbers d and f, then d + f > d.
Decimal numbers cannot be directly compared
What we have learned so far, is that we must throw away all intuition we have gained in math class and programming with integers. Use decimal numbers cautiously. For example, the statement for(double d = 0.1; d != 0.3; d += 0.1) is in effect a disguised never ending loop! The mistake is to compare decimal numbers directly with each other. You should adhere to the following guide lines.
Avoid equality tests between two decimal numbers. Refrain from if(a == b) {..}, use if(Math.abs(a-b) < tolerance) {..} where tolerance could be a constant defined as e.g. public static final double tolerance = 0.01
Consider as an alternative to use the operators <, > as they may more naturally describe what you want to express. For example, I prefer the form
for(double d = 0; d <= 10.0; d+= 0.1) over the more clumsy
for(double d = 0; Math.abs(10.0-d) < tolerance; d+= 0.1)
Both forms have their merits depending on the situation though: When unit testing, I prefer to express that assertEquals(2.5, d, tolerance) over saying assertTrue(d > 2.5) not only does the first form read better, it is often the check you want to be doing (i.e. that d is not too large).
WYSINWYG - What You See Is Not What You Get
WYSIWYG is an expression typically used in graphical user interface applications. It means, "What You See Is What You Get", and is used in computing to describe a system in which content displayed during editing appears very similar to the final output, which might be a printed document, a web page, etc. The phrase was originally a popular catch phrase originated by Flip Wilson's drag persona "Geraldine", who would often say "What you see is what you get" to excuse her quirky behavior (from wikipedia).
Another serious trap programmers often fall into, is thinking that decimal numbers are WYSIWYG. It is imperative to realize, that when printing or writing a decimal number, it is not the approximated value that gets printed/written. Phrased differently, Java is doing a lot of approximations behind the scenes, and persistently tries to shield you from ever knowing it. There is just one problem. You need to know about these approximations, otherwise you may face all sorts of mysterious bugs in your code.
With a bit of ingenuity, however, we can investigate what really goes on behind the scene. By now we know that the number 0.1 is represented with some approximation.
System.out.println( 0.1d );
0.1
We know 0.1 is not 0.1, yet 0.1 is printed on the screen. Conclusion: Java is WYSINWYG!
For the sake of variety, let's pick another innocent looking number, say 2.3. Like 0.1, 2.3 is an approximated value. Unsurprisingly when printing the number Java hides the approximation.
System.out.println( 2.3d );
2.3
To investigate what the internal approximated value of 2.3 may be, we can compare the number to other numbers in a close range.
double d1 = 2.2999999999999996d;
double d2 = 2.2999999999999997d;
System.out.println( d1 + " " + (2.3d == d1) );
System.out.println( d2 + " " + (2.3d == d2) );
2.2999999999999994 false
2.3 true
So 2.2999999999999997 is just as much 2.3 as the value 2.3! Also notice that due to the approximation, the pivoting point is at ..99997 and not ..99995 where you ordinarily round round up in math. Another way to get to grips with the approximated value is to call upon the services of BigDecimal.
System.out.println( new BigDecimal(2.3d) );
2.29999999999999982236431605997495353221893310546875
Now, don't rest on your laurels thinking you can just jump ship and only use BigDecimal. BigDecimal has its own collection of traps documented here.
Nothing is easy, and rarely anything comes for free. And "naturally", floats and doubles yield different results when printed/written.
System.out.println( Float.toString(0.1f) );
System.out.println( Double.toString(0.1f) );
System.out.println( Double.toString(0.1d) );
0.1
0.10000000149011612
0.1
According to the slides from Joseph D. Darcy's blog a float approximation has 24 significant bits while a double approximation has 53 significant bits. The morale is that In order to preserve values, you must read and write decimal numbers in the same format.
Division by 0
Many developers know from experience that dividing a number by zero yields abrupt termination of their applications. A similar behaviour is found is Java when operating on int's, but quite surprisingly, not when operating on double's. Any number, with the exception of zero, divided by zero yields respectively ∞ or -∞. Dividing zero with zero results in the special NaN, the Not a Number value.
System.out.println(22.0 / 0.0);
System.out.println(-13.0 / 0.0);
System.out.println(0.0 / 0.0);
Infinity
-Infinity
NaN
Dividing a positive number with a negative number yields a negative result, while dividing a negative number with a negative number yields a positive result. Since division by zero is possible, you'll get different result depending on whether you divide a number with 0.0 or -0.0. Yes, it's true! Java has a negative zero! Don't be fooled though, the two zero values are equal as shown below.
System.out.println(22.0 / 0.0);
System.out.println(22.0 / -0.0);
System.out.println(0.0 == -0.0);
Infinity
-Infinity
true
Infinity is weird
In the world of mathematics, infinity was a concept I found hard to grasp. For example, I never acquired an intuition for when one infinity were infinitely larger than another. Surely Z > N, the set of all rational numbers is infinitely larger than the set of natural numbers, but that was about the limit of my intuition in this regard!
Fortunately, infinity in Java is about as unpredictable as infinity in the mathematical world. You can perform the usual suspects (+, -, *, / on an infinite value, but you cannot apply an infinity to an infinity.
double infinity = 1.0 / 0.0;
System.out.println(infinity + 1);
System.out.println(infinity / 1e300);
System.out.println(infinity / infinity);
System.out.println(infinity - infinity);
Infinity
Infinity
NaN
NaN
The main problem here is that the NaN value is returned without any warnings. Hence, should you foolishly investigate whether a particular double is even or odd, you can really get into a hairy situation. Maybe a run-time exception would have been more appropriate?
double d = 2.0, d2 = d - 2.0;
System.out.println("even: " + (d % 2 == 0) + " odd: " + (d % 2 == 1));
d = d / d2;
System.out.println("even: " + (d % 2 == 0) + " odd: " + (d % 2 == 1));
even: true odd: false
even: false odd: false
Suddenly, your variable is neither odd nor even!
NaN is even weirder than Infinity
An infinite value is different from the maximum value of a double and NaN is different again from the infinite value.
double nan = 0.0 / 0.0, infinity = 1.0 / 0.0;
System.out.println( Double.MAX_VALUE != infinity );
System.out.println( Double.MAX_VALUE != nan );
System.out.println( infinity != nan );
true
true
true
Generally, when a double have acquired the value NaN any operation on it results in a NaN.
System.out.println( nan + 1.0 );
NaN
Conclusions
Decimal numbers are approximations, not the value you assign. Any intuition gained in math-world no longer applies. Expect a+b = a and a != a/3 + a/3 + a/3
Avoid using the ==, compare against some tolerance or use the >= or <= operators
Java is WYSINWYG! Never believe the value you print/write is approximated value, hence always read/write decimal numbers in the same format.
Be careful not to overflow your double, not to get your double into a state of ±Infinity or NaN. In either case, your calculations may be not turn out as you'd expect. You may find it a good idea to always check against those values before returning a value in your methods.
It's called loss of precision and is very noticeable when working with either very big numbers or very small numbers. The binary representation of decimal numbers with a radix is in many cases an approximation and not an absolute value. To understand why you need to read up on floating number representation in binary. Here is a link: http://en.wikipedia.org/wiki/IEEE_754-2008. Here is a quick demonstration:
in bc (An arbitrary precision calculator language) with precision=10:
(1/3+1/12+1/8+1/15) = 0.6083333332
(1/3+1/12+1/8) = 0.541666666666666
(1/3+1/12) = 0.416666666666666
Java double:
0.6083333333333333
0.5416666666666666
0.41666666666666663
Java float:
0.60833335
0.5416667
0.4166667
If you are a bank and are responsible for thousands of transactions every day, even though they are not to and from one and same account (or maybe they are) you have to have reliable numbers. Binary floats are not reliable - not unless you understand how they work and their limitations.
While BigDecimal can store more precision than double, this is usually not required. The real reason it used because it makes it clear how rounding is performed, including a number of different rounding strategies. You can achieve the same results with double in most cases, but unless you know the techniques required, BigDecimal is the way to go in these case.
A common example, is money. Even though money is not going to be large enough to need the precision of BigDecimal in 99% of use cases, it is often considered best practice to use BigDecimal because the control of rounding is in the software which avoids the risk that the developer will make a mistake in handling rounding. Even if you are confident you can handle rounding with double I suggest you use helper methods to perform the rounding which you test thoroughly.
This is primarily done for reasons of precision. BigDecimal stores floating point numbers with unlimited precision. You can take a look at this page that explains it well. http://blogs.oracle.com/CoreJavaTechTips/entry/the_need_for_bigdecimal
When BigDecimal is used, it can store a lot more data then Double, which makes it more accurate, and just an all around better choice for the real world.
Although it is a lot slower and longer, it's worth it.
Bet you wouldn't want to give your boss inaccurate info, huh?
Another idea: keep track of the number of cents in a long. This is simpler, and avoids the cumbersome syntax and slow performance of BigDecimal.
Precision in financial calculations is extra important because people get very irate when their money disappears due to rounding errors, which is why double is a terrible choice for dealing with money.