Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Leibniz Formula to compute PI

491 views
Skip to first unread message

karinova

unread,
Oct 9, 2002, 3:56:10 PM10/9/02
to
I am trying to make a class that performs the Leibniz Formula to compute PI.

I cant seem to make it add then subtract all the while increasing the
denominator by 2.

Any help would be greatly appreciated.

Thank you
Tyson

Rob

unread,
Oct 9, 2002, 5:39:41 PM10/9/02
to
Leibniz:
pi = 4(1 - 1/3 + 1/5 - 1/7 + 1/9 - 1/11 + ...)

why not just have a variable, let's say X which will have a value of +1 for
starters.
If you negate X, you get....-1. If you negate X again you get.....-(-X) => X
=> +1.
So now you know how to get the + - + - sequence going.
Your numerator is always 1, So X could be +1 for starters. Then X = -X at
each term.
The denominator simply is simply denominator+2.

Rob

always post some code if you run into problems.

karinova

unread,
Oct 9, 2002, 6:18:27 PM10/9/02
to
Thanks for the info, unfortunatley I am so green that your reply does little
to help.

I have pasted what I have so far,

public class leibniz
{
public static void main (String [] arg)
{
//Declare variables
int term = 0;
double numrtr = 1;
double denom = 1;
boolean add = (term % 2 == 0);
double sum = numrtr/denom;
int increase;
int termA;

//Run for specified number iterations (i < "number of interations")

for( int i = 0; i < 3; i++ )
{
//increment term by one each iteration
term++;
//increment denominator twice to achieve adding 2 to it each
iteration
denom++;
denom++;
}
//if term is odd subtract
if (add = false)

{
//this is supposed to add to the previous total
sum+= numrtr/denom;
}
//otherwise add if term is even
else
{
//this is supposed to subtract from the previos total
sum-= numrtr/denom;
}

//Print variable to see what they are after run like what "denom" is
System.out.println("**************************************************");
System.out.println("******* sum" + " " + sum + " " + "*****************");
System.out.println("******* Number of terms" + " " + term + " " + "****");
System.out.println("******* denominator " + " " + denom + " " + "******");
System.out.println("******* numerator " + " " + numrtr + " " + "******");
System.out.println("******* Num/Den" + " " + numrtr/denom + "*********");
System.out.println("**************************************************");


}

}
/**I think the problem is I havn't figured out how to add or subtract
the previous sum,
right now the sum is the latest total ie. if run for 2 iterations the
denominator
is 5 but becuase of "sum-= numrtr/(denom)" or something, it computes 1 +
1/5 or 1 - 1/5,
instead of 1-1/3+1/5....
right now with iterations set to 2, it takes 1 and subtracts 1/5 to get
.8, but it
should be 1/1-1/3+1/5 to get .866666667, as you can see it is not
*/
It keeps using the last number, I need variable to capture the most recent
calculation
then I want to use it to add or subtract from.

Thanks again
Tyson

"Rob" <r...@no.spam.pls> wrote in message
news:xm1p9.502851$Ag2.19...@news2.calgary.shaw.ca...

Jonas Lindström

unread,
Oct 9, 2002, 7:28:35 PM10/9/02
to
"karinova" <kn...@cruzio.com> wrote in comp.lang.java.help:

> Thanks for the info, unfortunatley I am so green that your
> reply does little to help.
>
> I have pasted what I have so far,
>
> public class leibniz

^
Leibniz

The convention in Java is that class names start with a capital.

> {
> public static void main (String [] arg)
> {
> //Declare variables
> int term = 0;
> double numrtr = 1;
> double denom = 1;
> boolean add = (term % 2 == 0);

add is set to true. You seem to think that you define a function
for add, but you are not. This is only calculated once.

> double sum = numrtr/denom;
> int increase;

Unused.

> int termA;

Unused.

>
> //Run for specified number iterations (i < "number of
> interations")
>
> for( int i = 0; i < 3; i++ )
> {
> //increment term by one each iteration
> term++;

Aha, term is only used for book-keeping. You don't need it! Use
the loop variable (i) instead.

> //increment denominator twice to achieve adding 2
> to it each
> iteration
> denom++;
> denom++;

Well - OK, though

denom += 2;

is preferred.

> }
> //if term is odd subtract
> if (add = false)

A common beginner's error in C, namely using = instead of == in
conditions, has been eliminated in Java by introducing the boolean
type - *except* for the boolean type itself. What you do here is
setting add to false and then testing it. The result will of
course always be false.

To test boolean variables, *always* use

if (condition) or if (!condition)

Do not write

if (condition == true) //etc.


>
> {
> //this is supposed to add to the previous total
> sum+= numrtr/denom;
> }
> //otherwise add if term is even
> else
> {
> //this is supposed to subtract from the previos
> total
> sum-= numrtr/denom;
> }

Besides, you don't need the if/else. "Rob" had a good suggestion
in a previous post - use a sign variable.

int sign = 1;

and on each loop iteration you flip the sign by negating:

sign = -sign;

and then multiply the next term with `sign'.

Jonas

--
Use spaces instead of tabs.

Russell Smithies

unread,
Oct 9, 2002, 7:59:39 PM10/9/02
to
why are you trying to do it the long way?
a simple for loop will do

int limit = 100; //or however many iterations u want
double sum = -1.0;

for(int i = 3, j = 1; i < limit; i +=2, j++){
if(j % 2 = 0) // if j is even
sum += ( 1 / i );
sum -= ( 1 / i ); // else
}

you may have to cast to double or it might be better to use floats.


Russell


"Jonas Lindström" <jona...@chello.se> wrote in message
news:Xns92A3F50D5B5A...@193.150.195.50...

Jonas Lindström

unread,
Oct 10, 2002, 8:41:01 AM10/10/02
to
"Russell Smithies" <russell.D...@ATxtra.DOTco.DOTnz>
wrote in comp.lang.java.help:

> why are you trying to do it the long way?
> a simple for loop will do

Since you top-post, it is hard to see who you reply to, but I'll
assume it was me.

When answering homework questions, I try to abstain from posting
complete solutions. I think it is better if the student tries to
work out a solution on his/her own.

However, sometimes you can learn a lot from a reading a complete
solution - provided it is correct.

>
> int limit = 100; //or however many iterations u want
> double sum = -1.0;


double sum = 1.0;

The first term in the series is 1.

>
> for(int i = 3, j = 1; i < limit; i +=2, j++){
> if(j % 2 = 0) // if j is even

This does not compile. ITYM

if (j % 2 == 0)

> sum += ( 1 / i );
> sum -= ( 1 / i ); // else

The indentation makes it look like the second line also belongs to
the if, which is misleading.

> }
>
> you may have to cast to double or it might be better to use
> floats.

Actually you cannot use ints at all as you have done; (1 / i )
when i is an int > 1 will always be zero, so the entire loop above
does nothing.

Regarding the algorithm: be aware that Leibniz formula to
calculate pi converges *extremely* slowly. With 100 terms you only
get one (1) correct decimal. Try a million terms.

You get better accuracy by starting with the smallest term.

public static double calculate_pi(int terms) {

double sum = 0;
int limit = terms * 2 - 1;
int sign = (limit - 1) % 4 == 0 ? +1 : -1;

for (int i = limit; i > 0; i -= 2, sign = -sign) {
sum += (double) sign / i;
}
return 4 * sum;
}

<snip>

Knute Johnson

unread,
Oct 10, 2002, 12:48:05 PM10/10/02
to
Jonas Lindström wrote:

>Regarding the algorithm: be aware that Leibniz formula to
>calculate pi converges *extremely* slowly. With 100 terms you only
>get one (1) correct decimal. Try a million terms.
>
>

I was surprised at how many iterations it takes.

>You get better accuracy by starting with the smallest term.
>
>

Why would that be? I am surprised to see the answer is different if you
add the terms in reverse order but the conclusion that smallest to
largest is more accurate isn't born out with my test code.

public class test {
public static void main(String[] args) {
double n = 1.0;
double numerator = 1.0;
// int numerator = 1;
long time = System.currentTimeMillis();
for (long i=3; i<=1000000003L; i+=2) {
n -= numerator/i;
// n -= (double)numerator/i;
numerator = -numerator;
}
System.out.println(4.0*n);

n = 1.0;
numerator = 1.0;
for (long i=1000000003L; i>1; i-=2) {
n -= numerator/i;
numerator = -numerator;
}
System.out.println(4.0*n);

System.out.println(Math.PI);
System.out.println(System.currentTimeMillis()-time);
}
}

3.141592651589258
3.1415926419886526
3.141592653589793
85125

knute...

Russell Smithies

unread,
Oct 10, 2002, 7:29:51 PM10/10/02
to
I never tried to compile it, it was a suggested approach that might work
with a bit of fiddling.
When dealing with "homework" questions, it is more a matter of pointing out
a possible path than giving out code that is optimized.

An obvious improvment to your code, if you're going to run a for loop
1000000 times, is to run it backwards.
Try writing your loops as:

for (i = N; --i >= 0; ) {
// do something
}


It usually runs 3x as fast :-)

"Jonas Lindström" <jona...@chello.se> wrote in message

news:Xns92A395B25FCC...@193.150.195.50...

Knute Johnson

unread,
Oct 10, 2002, 8:02:31 PM10/10/02
to
Russell Smithies wrote:

>An obvious improvment to your code, if you're going to run a for loop
>1000000 times, is to run it backwards.
>Try writing your loops as:
>
>for (i = N; --i >= 0; ) {
> // do something
>}
>
>
>It usually runs 3x as fast :-)
>
>
>

Why would that be? This conclusion is not born out by test on my
computer anyway. P4, 1.6Ghz, Winblows XP Home. Java 1.4.1.

public class test3 {


public static void main(String[] args) {

final int N = 100000000;

long time = System.currentTimeMillis();
for (int i=N; --i>=0;) {
int x = 2;
++x;
}
System.out.println(System.currentTimeMillis()-time);

time = System.currentTimeMillis();
for (int i=0; i<N; i++) {
int x = 2;
++x;
}
System.out.println(System.currentTimeMillis()-time);
}
}

375
189

knute...

Russell Smithies

unread,
Oct 10, 2002, 8:35:23 PM10/10/02
to
run it thru the java profiler and compare times spent in the for loop
or look at this:

http://www.javaworld.com/javaworld/jw-04-1997/jw-04-optimize.html

I guess it may have been 'fixed' in jdk1.4.1 but there's defiantly a huge
difference in jdk1.3.1
you also need to take into account the time taken for the jvm to start when
comparing the results


"Knute Johnson" <kn...@frazmtn.com> wrote in message
news:3DA61517...@frazmtn.com...

Jonas Lindström

unread,
Oct 11, 2002, 7:39:27 AM10/11/02
to
[posted and mailed]

Knute Johnson <kn...@frazmtn.com> wrote in comp.lang.java.help:

> Jonas Lindström wrote:
>
>>Regarding the algorithm: be aware that Leibniz formula to
>>calculate pi converges *extremely* slowly. With 100 terms you
>>only get one (1) correct decimal. Try a million terms.
>>
>>
> I was surprised at how many iterations it takes.
>
>>You get better accuracy by starting with the smallest term.
>>
>>
> Why would that be? I am surprised to see the answer is
> different if you add the terms in reverse order but the
> conclusion that smallest to largest is more accurate isn't
> born out with my test code.

That is an interesting question indeed. Perhaps I should have made
some tests on the Leibniz' series before coming up with my
somewhat general statement. Oh well... :)

In general when computing the sum of an infinite series, one
should be aware of the potential effects of truncation errors. A
floating point number only has so many significant digits.

Consider the sum of the geometric series

s = 1 + 0.98 + (0.98)^2 + (0.98)^3 + ...

[^ means exponentiation]

We know the sum of this series; it is 1/(1 - 0.98) = 50.

Now we would like to calculate the sum by adding terms. Assume
that we have a machine with four significant digits. The machine
will represent floating point numbers in scientific form like in
the right column below:

Exact Scientific
25000 2.5E4
114.3 1.143E2
1.35 1.35E0
0.02456 2.456E-2

Naturally we hope to get an answer with four digit accuracy. (We
happen to know that the answer is 50). This means that we would
like the rest term to be less than 0.005. That will happen after
n = 455.

[ rest(n) = k^(n+1) + k^(n+2) + ... = k^(n+1) / (1-k) ]


So we start adding:

n a(n) s(n)
------------------------------------
0 1.000 1.000
1 0.9800 1.980
2 0.9604 2.940
3 0.9412 3.881
4 0.9224 4.803
...
259 0.0053 49.73
260 0.0052 49.74
261 0.0051 49.75
262 0.0050 49.76
263 0.0049 49.76

We get each term a(n) by multiplying the previous term a(n-1) with
0.98. Eventually a(n) will be so small that it has no effect on
the sum. It happens when a(n) < 0.005, since the sum only can
store two integer digits and two fraction digits. As it turns out,
the sum will be 49.76.

The rest term in this case is ~ .24.

So why would we want to start with smallest terms? Well, we did
miss out a lot of terms by adding a large number to a small
number. If we start with n = 455, this is what happens:

n a(n) s(n)
------------------------------------
455 1.018E-4 1.018E-4
454 1.039E-4 2.057E-4
453 1.060E-4 3.117E-4
452 1.082E-4 4.199E-4
451 1.104E-4 5.303E-4
...
262 0.005031 0.2462
...
0 1.003 50.18

When we reach n = 262, the sum is approximately equal to the
missing rest term in the previous case. The final sum is not equal
to 50 either due to rounding errors, but we should get closer to
the right answer, and we did.

Of course, none of this usually matters, since in reality you have
about 16 decimal digits at your disposal, and rarely needs more
than a few. But it can be good to know nevertheless.

--
Jonas Lindström (jona...@chello.se)
Stockholm, Sweden

Knute Johnson

unread,
Oct 11, 2002, 12:59:33 PM10/11/02
to
Thanks for the excellent explaination Jonas! If I get some more free
time I'll have to try some experiments with different precision and some
other equations just for fun.

knute...

Russell Smithies

unread,
Oct 12, 2002, 12:36:06 AM10/12/02
to
you also get different answers using floats, long or double.
reversing the order of operations also gives different answers due to the
way rounding and overflow is handled.


"Knute Johnson" <kn...@frazmtn.com> wrote in message
news:3DA70375...@frazmtn.com...

0 new messages