Don't know if this question belongs in the advanced or beginners java section, so am putting in the intermediate section. Hope this is right, but please move if not.

I have a worry when it comes to floating point values loss of precision. Maybe you guys can help to substiate my worry, or provide a solution to it.

I'm writing a financial application that it working with decimal numbers. Therefore i can't use float or double. Use bigdecimal instead. I need to take 'a decimal value' to the power of 'another decimal value'.

There is the function Math.pow(double a, double b) that returns a double.

If I do this for example:

BigDecimal one = new BigDecimal("1.234"); BigDecimal two = new BigDecimal("1.5");

Maybe, run it and get the answer and compare it using a calculator that is accurate to as many places as you can find.

That specific example isn't all that complex, so it should be fairly accurate. It is equivilent to square root of 1.234^3. My Ti-85 graphing calculator returns 1.37079571928, which is precise enough for most applications.

Running the program with 1.5 on Linux the result returned is 1.3707957192813232, without using BigDecimal at the end, using it before the pow90 call is pointless. Is this precise? No, since the real result is irrational, you will never have precision. How precise you need, depends on the situation. 4 significant digits might be peachy in one case, and death or massive problems in another. [ September 13, 2006: Message edited by: Robert Hill ]

Darryl Nortje
Ranch Hand

Joined: Jun 11, 2002
Posts: 140

posted

0

Hi there,

Thanks for the reply. I'm not quite sure I follow. Albeit that my example might be bad, there probably is instances where even the rounding off wouldn't help. If you look at example below, it is much much simpler, yet even with rounding gives the totally incorrect result.

double x = 1.0; double y = 0.8;

System.out.println(x - y);

prints out 0.19999999999999996.

So perhaps ignore my example and how close it is to the real answer. There might be some doubles when you call Math.pow() that also give totally incorrect results that not even rounding will help.

So is there some other way (using BigDecimal) that you can do something similar to Math.pow() without loosing precision.

First you say that you are deliberately not using float and double because you don't want to loose precision, but then you show a piece of code that does convert your BigDecimals to doubles and back. So you are using doubles, even though you just said you didn't want to use them. Ofcourse the precision will not be better than what double provides if you do that.

The types float and double store floating point numbers in binary form. Just like you cannot express some numbers exactly in decimal form, such as 1/3 = 0.33333..., there are numbers that you cannot express exactly in binary form.

The number 0.2 in binary form is written as: 0.00110011001100110011... Note the recurring pattern, just like 0.3333... in decimal; the number just can't be represented exactly in binary form.

Try this instead of your code:

Surprise, surprise! It prints 0.200000 instead of 0.19999999999999996. That's because the formatter that printf() uses rounds the number correctly.

The result "0.19999...96" isn't "totally incorrect". It's correct in the context of the IEEE 754 specification for floating point numbers. [ September 13, 2006: Message edited by: Jesper Young ]