HiveBrain v1.2.0
Get Started
← Back to all entries
patternjavaMinor

Calculating Pi with Android

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
withcalculatingandroid

Problem

I'm kind of new to Java but I am writing an Android app. Right now I'm working on an async task to calculate Pi but when I run it the memory usage increases alarmingly (+5MB per second). This one piece of code may need to run thousands of times so it is important that it be very optimized.

protected BigDecimal doInBackground(Object... params) {
        digits = (int)params[0];
        piView = (TextView)params[1];
        boolean add = true;
        BigDecimal pi = new BigDecimal(0.0);
        for(int i=1; pi.setScale(digits, BigDecimal.ROUND_DOWN).equals(realPi) == false; i++){
            if(add){
                pi = pi.add(new BigDecimal(4.0 / (-1 + (i*2))));
                add = false;
            }
            else {
                pi = pi.subtract(new BigDecimal(4.0 / (-1 + (i*2))));
                add = true;
            }
        }
        return pi;
    }


This one piece of code may need to run thousands of times so it is important that it be very optimized.

Solution

boolean add = true;
    for(int i=1; pi.setScale(digits, BigDecimal.ROUND_DOWN).equals(realPi) == false; i++){
        if(add){
            pi = pi.add(new BigDecimal(4.0 / (-1 + (i*2))));
            add = false;
        }
        else {
            pi = pi.subtract(new BigDecimal(4.0 / (-1 + (i*2))));
            add = true;
        }
    }


You don't need an add variable. Consider

int i = 1;
    while (!pi.setScale(scale, BigDecimal.ROUND_DOWN).equals(realPi)) {
        pi = pi.add(new BigDecimal(4.0 / i));
        i += 2;
        pi = pi.subtract(new BigDecimal(4.0 / i));
        i += 2;
    }


This may do one extra subtract operation, but it does half as many equals operations. And it doesn't waste time on setting and checking a variable just to alternate between two operations.

We don't need the (-1 + (i*2)) part. If we increment by 2 instead of 1, we get the same stream of values with strictly less math. 1, 3, 5, 7, 9, 11, ...

I changed the == false to the more idiomatic !.

I also changed digits to scale as I had trouble reading the original.

BigDecimal gives precise results, not quick results. It is quite possible that you are hitting real limits of the format. It's unclear at the moment why you are calculating \$\pi\$. With more context, we might be able to give more help.

Code Snippets

boolean add = true;
    for(int i=1; pi.setScale(digits, BigDecimal.ROUND_DOWN).equals(realPi) == false; i++){
        if(add){
            pi = pi.add(new BigDecimal(4.0 / (-1 + (i*2))));
            add = false;
        }
        else {
            pi = pi.subtract(new BigDecimal(4.0 / (-1 + (i*2))));
            add = true;
        }
    }
int i = 1;
    while (!pi.setScale(scale, BigDecimal.ROUND_DOWN).equals(realPi)) {
        pi = pi.add(new BigDecimal(4.0 / i));
        i += 2;
        pi = pi.subtract(new BigDecimal(4.0 / i));
        i += 2;
    }

Context

StackExchange Code Review Q#146539, answer score: 3

Revisions (0)

No revisions yet.