// Demo 13: ParabolaApplet.java // The Area Under A Parabola // A Java Applet // // Finds the area of a parabolic shaped plane region // Graphically illustrates the area finding process // // by Charles W. Neville, 1998 // Copyright Charles W. Neville, 1998 // Illustrates for loops and if - else. // Illustrates use of double precision floating point numbers. // Illustrates use of class Random in simulations. // Illustrates drawing figures on the Applet Panel // Illustrates breaking a program up into separate procedures. // Illustrates methods which return values (rather than void). // Illustrates finding definite integrals (areas) by a Monte Carlo method. // Finding Areas Using A Monte Carlo method: // // Monte Carlo methods are an important class of methods for scientific // computing. In a Monte Carlo method, one uses a random process // (pseudo-random process actually) to simulate something in nature or // mathematics, usually something quite complex. Monte Carlo methods are named // after the famous casino in Monte Carlo. // // Here is how this program works. We wish to compute an approximation to the // area of the plane region bounded by the parabola y = 1 - x*x. and the x axis // (the area under the parabola). We do this in the following manner: // Simulate throwing 10,000 darts at rectangle of width 2 and height 1 with // vertices (corners) at (-1, 0), (1, 0), (1, 1) and (-1, 1). Note that you // could draw the region under the parabola and have it just touch the edges of // the rectangle (be inscribed in the rectangle). Count the number of darts // which hit the parabolic region, and at the end, compute the fraction of // darts which hit the parabolic region by dividing the total number of hits by // 10,000. Now the fraction f of darts hitting the parabolic region is equal // to // // areaOfParabolicRegion/AreaOfRectangle, // // except for statistical error. Now areaOfRectangle = 2*1 = 2. Thus the // fraction f is equal to areaOfParabolicRegion/2, except for statistical // error. Multiply f by 2 to get an approximation to the area of the parabolic // region, // // areaOfParabolicRegion = 2*f // // approximately. (Approximately because of the statistical error.) // Drawing Parabolas and Darts: // // We will draw the parabola y = 1 - x*x by calculating the (x, y) coordinates // of successive points on the parabola and drawing small filled ovals centered // at x and y (the same way you graph curves by plotting points). We will use // Java's fillOval method to draw the small filled ovals. We will also draw a // rectangle into which the parabola is inscribed by using Java's drawRect // method. We will have to scale the values of x and y and convert them to // integers because the coordinates used by all of Java's figure drawing // methods are measured in pixels, starting from the upper left hand corner of // the Applet Panel. (Obviously, wouldn't want to draw a parabola 2 pixels // wide by 1 pixel tall.) // // We will also draw the dart hits as small filled ovals. As the program runs, // the user will be able to see where the darts are hitting, and will be able // to visually determine how many darts hit outside the parabolic region and // how many hit inside. (However, we will only draw every 100th dart, since we // are throwing 10,000 darts, so the user's visual count will differ from the // actual count. // Dividing the Labor // // We will do our calculations as well as our drawing in the paint method. // Because we are going to be doing so many different things in the paint // method, computing the area, drawing geometric figures, drawing where darts // hit, we need a way of dividing the work into smaller tasks. So we shall // PROCEDURIZE our program. This means we will write a separate method for // each task, and then call each method, as appropriate, in the start method. // (The name PROCEDURIZE comes from the fact that in other languages, methods // are frequently called procedures.) From now on, most programs we write will // be divided up into separate procedures (methods). // When I ran this program 4 consecutive times, I got the following approximate // values for the area of the parabolic region: 1.3298, 1.3316, 1.3406, and // 1.3340. The exact value (from calculus) is 4/3 = 1.33333333... . The // approximation is pretty good, don't you think? // By the way, very well paid people on Wall Street actually write programs to // evaluate very complicated definite integrals using Monte Carlo methods in // this very way. import java.applet.Applet; import java.awt.*; import java.util.*; // have to import java.util.* because Java needs to // know what class Random is. public class ParabolaApplet extends Applet { final int numThrows = 10000; // number of dart throws. int numHits; // number of hits in parabolic region. double x, y; // coordinates of random point in rectangle. double areaOfParabolicRegion; // obviously, the area of the // parabolic region. Random random = new Random(); // declare and create a new Random object. final int xPanelOrigin = 125, yPanelOrigin = 125; // panel coordinates in pixels of point // (x, y) = (0,0) on boundary of rectangle. final int panelScaleFactor = 100; // 1 unit in (x,y) coordinate system // corresponds to 100 pixels on Applet Panel. final int appletWidth= 350, appletHeight = 400; // the Applet Panel's // width and height, obviously. // init() is always called when the Applet is first loaded, but is only // called once, and and so is a good place to initialize variables that do // not need to be reinitialized if the Applet is restarted. public void init() { // need to set size here in init because we need to know exactly // how large the Applet Panel is to be sure our scaling is correct. // The size we set here overrides any sizing done in the html file. setSize(appletWidth, appletHeight); // all other initializations were made at declaration time or are made // in start, so we don't need to do anything. } // start is called right after init, and every time the applet is restarted, // so it is a good place to initialize variables that should be // reinitialized upon restarting. public void start() { // initialize these here so they will be set back to 0 // every time the Applet is restarted. numHits = 0; } // We do our our calculations in paint, since we need to draw // as we calculate. public void paint( Graphics g ) { numHits = 0; // initialize this here so it will be set back to 0 // every time we repeat our calculations (say if the Applet // is restarted, or is repainted because we clicked on //another window). drawOurRectangle(g); drawOurParabola(g); // Go through this loop exactly numThrows times (exactly 10,000 times), // throw darts randomly at the parabolic region, and draw every 100th // dart. for( int i = 1; i <= numThrows; i++ ) { // throw a dart at random throwDart(); // check to see if dart hit parabolic region, and if so, // update the number of hits if ( y <= 1 - x*x ) { numHits = numHits + 1; } // draw where every 100th dart hits. if ( i % 100 == 0 ) { drawHit(g, x, y); } } // What is area of parabolic region? areaOfParabolicRegion = calcArea(numHits, numThrows); // And draw the result on the Applet Panel g.drawString( "The area of the parabolic region is: " + areaOfParabolicRegion, 25, 200 ); } // Draw rectangle with corners (vertices) (-1, 0), (1, 0), (1, 1), (1, -1) // in the (x, y) coordinate system on the Applet's graphic context g. void drawOurRectangle(Graphics g) { int xCorner, yCorner; // x and y screen (panel) coordinates in pixels of // upper left corner (vertex) of rectangle. int width,height; // width and height in pixels of rectangle. xCorner = (-1)*panelScaleFactor + xPanelOrigin; // x = -1 yCorner = - panelScaleFactor + yPanelOrigin; // y = 1, but the // Applet Panel coordinate system is upside down, // because y positions are measured by moving down // in pixels from top of panel. width = 2*panelScaleFactor; height = panelScaleFactor; // And now, draw the rectangle g.drawRect(xCorner, yCorner, width, height); } // Draw parabola y = 1 - x*x inscribed in rectangle. void drawOurParabola(Graphics g) { double x, y; // x and y coordinates of points on parabola y = 1 - x*x. double xIncrement; // increment in x while drawing parabola. int width,height; // width and height in pixels of parabola. int xScreen, yScreen; // x and y screen (panel) coordinates // corresponding to x and y. width = 2*panelScaleFactor; height = panelScaleFactor; // Start at (-1, 0) in (x, y) coordinate system. x = -1.0; y = 0.0; // x increment is 2/height because we draw points in height steps, and // the total increment in x from left to right is 2. xIncrement = (double) 2 / height; // Careful! Be sure we have a double // here because otherwise, if everything in the // quotient is an integer, / is integer division, // and then xIncrement would be 0. // And now, draw the parabola by drawing small filled ovals at // successive points of the parabola using a for loop. for ( int i = 1; i <= height; i++ ) { xScreen = (int) (x*panelScaleFactor) + xPanelOrigin; // note the casts. yScreen = - (int) (y*panelScaleFactor) + yPanelOrigin; // Applet Panel // coordinate system is upside down, because y // positions are measured by moving down in pixels // from top of panel. // draw a 3 pixel wide by 3 pixel high filled oval where dart hit. // IMPORTANT: The filled oval has to be at least 3 by 3 to be // visible when it is drawn. g.fillOval(xScreen, yScreen, 3, 3); // increment x and y. x = x + xIncrement; y = 1 - x*x; // apply equation for parabola. } } // Throw a dart at rectangle by randomly generating x and y values // between -1.0 and 1.0 for x, and 0.0 and 1.0 for y. public void throwDart() { // Randomly generate x and y values between 0.0 and 1.0 x = random.nextDouble(); y = random.nextDouble(); // But want random values for x to be between -1.0 and 1.0 x = -1 + 2*x; } // Calculate area of parabolic region. // This is our first example of a method that returns a value, // just like a mathematical function. double calcArea(int numHits, int numThrows) { double f; // fraction of times dart hit parabolic region. // what fraction of the darts hit the parabolic region? // careful! Convert numHits to a double first because / means // means INTEGER DIVISION when only integers are involved. f = (double) numHits / numThrows; // Note: The above (double) numHits is our first cast. Casting // means changing one type to another compatible type. // return the area of the parabolic region return 2*f; } void drawHit(Graphics g, double x, double y) { int xScreen, yScreen; // x and y screen (panel) coordinates // corresponding to x and y. xScreen = (int) (x*panelScaleFactor) + xPanelOrigin; // note the casts. yScreen = - (int) (y*panelScaleFactor) + yPanelOrigin; // Applet panel // coordinate system is upside down, because y // positions are measured by moving down in pixels // from top of panel. // draw a 3 pixel wide by 3 pixel high filled oval where dart hit. // IMPORTANT: The filled oval has to be at least 3 by 3 to be // visible when it is drawn. g.fillOval(xScreen, yScreen, 3, 3); } }