10
\$\begingroup\$

I've written a little program to calculate pi using the Nilakantha series:

For this formula, take three and start alternating between adding and subtracting fractions with numerators of 4 and denominators that are the product of three consecutive integers which increase with every new iteration. Each subsequent fraction begins its set of integers with the highest one used in the previous fraction. Carry this out even a few times and the results get fairly close to pi. (http://www.wikihow.com/Calculate-Pi)

I don't really understand other ways of calculating pi, or they take too long to perform.

echo "Enter scale please"
read SCALE
VALUE=2
PI=3
FITNESS=1
while true
do
PI=$(echo "scale=$SCALE;$PI+(4/($VALUE*($VALUE+1)*($VALUE+2)))-(4/(($VALUE+2)*($VALUE+3)*($VALUE+4)))" | bc)
VALUE=$(($VALUE+4))
FITNESS=$(($FITNESS+1))
echo "###############"
echo "--> $FITNESS // $VALUE"
echo "$PI"
done

I would really like to know how to detect when I get the same output multiple times, so I can tell the program to terminate when it has reached the most accurate version of pi possible.

Also if you have other suggestions on how to improve the code and/or know a better way of calculating pi (with some explanation), I would like to hear.

\$\endgroup\$
13
\$\begingroup\$

I see a few things that could allow you to improve your program. First, though, I don't consider myself a bash expert, so there may well be better ways of doing these things.

Use a "shebang" line

As this question points out, you should always use a "shebang" line for your bash scripts. So the first line would be:

#!/usr/bin/env bash

Pass values as arguments

Rather than prompting for the SCALE value, it's generally better to use a command line argument. That way, the script can be reused by other shell scripts.

Provide a stopping mechanism

As each term is calculated, eventually, it will be equal to zero given the passed scale. This suggests a mechanism for stopping: check each term for 0 before adding it.

Indent do and while loops

I don't know of a bash style guide (there probably is one!) but I like to see the contents of loops indented to make it easier to read.

Putting it all together

Here's a modification of your script with all of these suggestions implemented:

bashpi.sh

#!/usr/bin/env bash
SCALE=$1
VALUE=2
PI=0
FITNESS=1
DELTA=3
while [ $(echo "$DELTA==0" |bc) != "1" ]
do
    PI=$(echo "$PI+$DELTA" | bc)
    DELTA=$(echo "scale=$SCALE;(4/($VALUE*($VALUE+1)*($VALUE+2)))-(4/(($VALUE+2)*($VALUE+3)*($VALUE+4)))" | bc)
    VALUE=$(($VALUE+4))
    FITNESS=$(($FITNESS+1))
    echo "###############"
    echo "--> $FITNESS // $VALUE"
    echo "$PI"
done

To better understand how this works, you can replace the three echo statements with this one:

echo "DELTA = ${DELTA} --> ${FITNESS} // ${VALUE} : ${PI}"

Sample output

With ./bashpi.sh 4, and the modified echo above I get this output:

DELTA = .1333 --> 2 // 6 : 3
DELTA = .0064 --> 3 // 10 : 3.1333
DELTA = .0012 --> 4 // 14 : 3.1397
DELTA = .0003 --> 5 // 18 : 3.1409
DELTA = .0001 --> 6 // 22 : 3.1412
DELTA = .0001 --> 7 // 26 : 3.1413
DELTA = .0001 --> 8 // 30 : 3.1414
DELTA = 0 --> 9 // 34 : 3.1415
\$\endgroup\$
  • \$\begingroup\$ I really appreciate the suggestions, but I don't completely understand how you've implemented the stopping feature, SCALE simply is how many numbers exist after the decimal point. There's probably something I'm not seeing here... \$\endgroup\$ – insanikov Jun 21 '15 at 18:17
  • \$\begingroup\$ It's a bit subtle. Basically, a value of 0.001 (=1e-3) with a scale of 3 is nonzero, but a value of 0.0005 (=5e-4) is considered to be equal to zero at a scale of 3, so when the next term becomes less than smaller than 1e-${SCALE}, the printable part of ${PI} is unlikely to change except in the least significant digit. A refinement would be to use ${SCALE}+1 in the while loop but it doesn't make much difference and this is slightly easier to understand. \$\endgroup\$ – Edward Jun 21 '15 at 21:08
  • \$\begingroup\$ I understand it now, I would have never come up with this. Thank you for the explanation. \$\endgroup\$ – insanikov Jun 22 '15 at 13:52

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.