Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #!/bin/bash
- # cannon.sh: Approximating PI by firing cannonballs.
- # This is a very simple instance of a "Monte Carlo" simulation:
- #+ a mathematical model of a real-life event,
- #+ using pseudorandom numbers to emulate random chance.
- # Consider a perfectly square plot of land, 10000 units on a side.
- # This land has a perfectly circular lake in its center,
- #+ with a diameter of 10000 units.
- # The plot is actually mostly water, except for land in the four corners.
- # (Think of it as a square with an inscribed circle.)
- #
- # We will fire iron cannonballs from an old-style cannon
- #+ at the square.
- # All the shots impact somewhere on the square,
- #+ either in the lake or on the dry corners.
- # Since the lake takes up most of the area,
- #+ most of the shots will SPLASH! into the water.
- # Just a few shots will THUD! into solid ground
- #+ in the four corners of the square.
- #
- # If we take enough random, unaimed shots at the square,
- #+ Then the ratio of SPLASHES to total shots will approximate
- #+ the value of PI/4.
- #
- # The reason for this is that the cannon is actually shooting
- #+ only at the upper right-hand quadrant of the square,
- #+ i.e., Quadrant I of the Cartesian coordinate plane.
- # (The previous explanation was a simplification.)
- #
- # Theoretically, the more shots taken, the better the fit.
- # However, a shell script, as opposed to a compiled language
- #+ with floating-point math built in, requires a few compromises.
- # This tends to lower the accuracy of the simulation, of course.
- DIMENSION=10000 # Length of each side of the plot.
- # Also sets ceiling for random integers generated.
- MAXSHOTS=1000 # Fire this many shots.
- # 10000 or more would be better, but would take too long.
- PMULTIPLIER=4.0 # Scaling factor to approximate PI.
- get_random ()
- {
- SEED=$(head -1 /dev/urandom | od -N 1 | awk '{ print $2 }')
- RANDOM=$SEED # From "seeding-random.sh"
- #+ example script.
- let "rnum = $RANDOM % $DIMENSION" # Range less than 10000.
- echo $rnum
- }
- distance= # Declare global variable.
- hypotenuse () # Calculate hypotenuse of a right triangle.
- { # From "alt-bc.sh" example.
- distance=$(bc -l << EOF
- scale = 0
- sqrt ( $1 * $1 + $2 * $2 )
- EOF
- )
- # Setting "scale" to zero rounds down result to integer value,
- #+ a necessary compromise in this script.
- # This diminshes the accuracy of the simulation, unfortunately.
- }
- # main() {
- # Initialize variables.
- shots=0
- splashes=0
- thuds=0
- Pi=0
- while [ "$shots" -lt "$MAXSHOTS" ] # Main loop.
- do
- xCoord=$(get_random) # Get random X and Y coords.
- yCoord=$(get_random)
- hypotenuse $xCoord $yCoord # Hypotenuse of right-triangle =
- #+ distance.
- ((shots++))
- printf "#%4d " $shots
- printf "Xc = %4d " $xCoord
- printf "Yc = %4d " $yCoord
- printf "Distance = %5d " $distance # Distance from
- #+ center of lake --
- # the "origin" --
- #+ coordinate (0,0).
- if [ "$distance" -le "$DIMENSION" ]
- then
- echo -n "SPLASH! "
- ((splashes++))
- else
- echo -n "THUD! "
- ((thuds++))
- fi
- Pi=$(echo "scale=9; $PMULTIPLIER*$splashes/$shots" | bc)
- # Multiply ratio by 4.0.
- echo -n "PI ~ $Pi"
- echo
- done
- echo
- echo "After $shots shots, PI looks like approximately $Pi."
- # Tends to run a bit high . . .
- # Probably due to round-off error and imperfect randomness of $RANDOM.
- echo
- # }
- exit 0
- # One might well wonder whether a shell script is appropriate for
- #+ an application as complex and computation-intensive as a simulation.
- #
- # There are at least two justifications.
- # 1) As a proof of concept: to show it can be done.
- # 2) To prototype and test the algorithms before rewriting
- #+ it in a compiled high-level language.
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement