using bigdecimal class

I was using Gregory-Leibniz series to calculate PI = 4 - 4/3 + 4/5 - 4/7 + 4/9 - 4/11 + ...

Something like:

double pi = 0.0;

int limit = 3000000;

for (int i = 0, y = 1; i <= limit; y+=2, i++)

{

if (y == 1)

pi = 4;

elseif (i % 2 == 0)

pi += (double)4/y;

else

pi -= (double)4/y;

System.out.println(String.format("Loop %d: %.20f", i, pi));}

Then I realized PI isn't going to be totally accurate according to IEEE Standard for Binary Floating-Point Arithmetic that java math calculation uses, so I was trying to use BigDecimal class (new to me), this is what I got initally...

BigDecimal pi =new BigDecimal("0.00");

int limit = 3000000;

for (int i = 0, y = 1; i <= limit; y += 2, i++)

{

if (y == 1)

pi =new BigDecimal("4.0");

elseif (i % 2 == 0)

pi = pi.add(new BigDecimal( Double.toString( (double) 4 / y )));

else

pi = pi.subtract(new BigDecimal( Double.toString( (double) 4 / y )));

System.out.println(String.format("Loop %d: %s", i, pi.toString()));

}

I realize that when I do the 4/y calculations involving both doubles... the result is probably stored according to the IEEE standards which is the thing to avoid... Is that correct? Is my PI result going to be accurate?

I noticed with this one decimals up to the 22nd place are all filled with some numbers in the calculations compared with the first one involving only double number calculations which had zero's starting around the 15th decimal.

Something like doesn't work and ends up with arithmeticexceptions...

pi = pi.subtract(new BigDecimal("4").divide(new BigDecimal(Integer.toString(y))));

So I'm actually confused about the right way of using BigDecimal class in this type of calculation to get accurate results. I do realize it's an immutable class and probably a bad idea to use it like this 3 million times in a loop.

[2950 byte] By [rugaea] at [2007-11-27 10:07:36]
# 1

When using the BigDecimal class, you should always use the String constructor. Otherwise, you will still end up with rounding errors.

But you can't use arbitrary precision in this case: how would 4/3 be represented as a BigDecimal? I'm pretty sure a double can calculate Pi more than accurate enough for your purpose.

prometheuzza at 2007-7-13 0:43:55 > top of Java-index,Java Essentials,Java Programming...
# 2

quoting from the API documentation on BigDecimal

"The BigDecimal class gives its user complete control over rounding behavior. If no rounding mode is specified and the exact result cannot be represented, an exception is thrown; otherwise, calculations can be carried out to a chosen precision and rounding mode by supplying an appropriate MathContext object to the operation."

That explains the arithmetic exceptions.

You would be advised to choose your scale first, (that would be the number of decimal places that you want to be using for your calculation. ) Then use the BigDecimal constructors that use the scale value. Construct your BigDecimal 4 outside of the loop so that you are not constructing it over and over again. And finally, read the documentation on how the scale of the result will depend upon the scale of the components going in.

A little reading and possibly re-reading of the documentation will help in the understanding of the BigDecimal class.

marlin314a at 2007-7-13 0:43:55 > top of Java-index,Java Essentials,Java Programming...
# 3

The series you have chosen converges to pi very slowly. If you really are interested in calculating a good aproximation for pi you should use a different algorithm. Some are listed in Wikipedia:

http://en.wikipedia.org/wiki/Computing_%CF%80

http://en.wikipedia.org/wiki/Category:Pi_algorithms

Note that the value of the constant Math.PI is within 2.2 *10^-16 of the true value. Do you really need an approximation that is more precise?

jsalonena at 2007-7-13 0:43:55 > top of Java-index,Java Essentials,Java Programming...
# 4

@OP: Iterating 3000000 times, BigDecimal (using MathContext(100) while dividing) produces the following output:

3.1415929869230154607126433801930823595057256412518204962337769682794011951274944118789621794318439448177957

and double produces the following:

3.1415929869229293

In both cases they are not really precise (only the underlined part is correct). So I suggest you keep it simple and stick with the primitive double.

prometheuzza at 2007-7-13 0:43:55 > top of Java-index,Java Essentials,Java Programming...
# 5

Just did more reading and it seems that BigDecimal is used more in currency to prevent rounding off errors when keeping 2 decimal places.

So does that mean a calculation such as for PI or another other looped calculations should be acceptable within 5 decimal places?

I'm making a calculations thing that needs fractions and extensive use of loops to calculate. Is using primitive double fine if I want to be accurate to the 5th decimal?

rugaea at 2007-7-13 0:43:55 > top of Java-index,Java Essentials,Java Programming...
# 6

> I was using Gregory-Leibniz series to calculate PI =

> 4 - 4/3 + 4/5 - 4/7 + 4/9 - 4/11 + ...

There are other formulae which might be more appropriate for high-precision calculations than this with the changing signs.

PI*PI/6 = 1 + 1/4 + 1/9 + 1/16 + 1/25 + ... + 1/n*n + ...

Similar issues arise with them however.

BIJ001a at 2007-7-13 0:43:55 > top of Java-index,Java Essentials,Java Programming...