//==========================================
//     Numerical Analysis WorkSheet Bisection Approximation
//==========================================
//   Bisection approximation for solving a single variable
// equation. This applet applies the Bisection Method to find>
// a root x of an equation of the form f(x)=0, for a given
// function f. The inputs to the applet are the function f(x),
// interval endpoints [a,b], tolerance e > 0, and the number
// of iterations. Subclass of Numerical Worksheet.
//
//                      
<< Bisection.java >>
//
//===========================================
// Copyright (C) 1999-2005 Dana M. Proctor
// Version 2.8 5/11/2005
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version
// 2 of the License, or (at your option) any later version. This
// program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied
// warranty of MERCHANTABILITY or FITNESS FOR A
// PARTICULAR PURPOSE. Seebr the GNU General Public
// License for more details. You should have received a copy
// of the GNU General Public License along with this program;
// if not, write to the Free Software Foundation, Inc., 59 Temple
// Place, Suite 330, Boston, MA 02111-1307 USA
// (http://opensource.org)
//
//============================================
// Revision History
// Changes to the code should be documented here and reflected
// in the present version number. Author information should
// also be included with the original copyright author.
//=============================================
// Version 1.0 Original Stand Alone Applet.
//             
1.1 Additional Error Checking of Input Data.
//             
1.2 Sub-Division into Numerical WorkSheet.
//             
1.3 Addition of Code to Save Output List Data.
//             
1.4 Additional Error Checking of Input Data
//                   
and Elimination of Clearing the TextField
//                  
Upon Errors.
//                      1.5 Intermediate Output.
//                      1.6 Package Creation/Inclusion.
//             
1.7 Minor Change check_data to getCheck_Data.
//             
1.8 mainBisection Class Method b=null Finished.
//             
1.9 Creation of Two Constructor Methods.
//             
2.0 Creation of Class Method getBisection_Root.
//             
2.1 GPL Inclusion & Basic JavaDoc Information.
//             
2.2 getFunctionValue Changed to NA_Utils Class.
//              2.3 Algorithm Source Documentation.
//              2.4 Format Intermediate Output Data.
//              2.5 Fix for Invalid Decimal Place in Tolerance
//             
2.6 Output Data Column Spacing via the Format Menu.
//              2.7 Fraction Input Implementation for Doubles.
//             
2.8 Correction of NA_Utils.convertFractionString.
//
//--------------------------------------------------------------------
//                  
danap_n_mt@users.sourceforge.net
//=============================================
package net.danap.numericalworksheet;
/**
 * The Bisection root approximation method implementation class.
 *
 * @author Dana M. Proctor
 * @version 2.8 5/11/2005
 */
class Bisection
{
      //=============================================
      // Creation of the class and instance field data types needed
      // to perform the Bisection Algorithm.
      //=============================================
   
      private static double bisectionRoot;
      private static boolean externalRoot=false;
   
      private int n, colWidth, decimalPlaces;
      private double endPointA, endPointB, tolerance;
   
      //=============================================
      // Bisection constructor used during normal access by the
      // Worksheet User. Default constructor object creation only
      // allowed by the class method:
     
//                             
<< mainBisection() >>
      //=============================================
   
      private Bisection()
      {
            super();
      }
   
      //=============================================
      // Bisection constructor that will allowed an outside class
      // access to the bisection approximation. Constructor new
      // object creation must be accessed through:
      //                 << getBisection_Root() >>
      //=============================================
   
      private Bisection(double A, double B)
      {
            endPointA = A;
            endPointB = B;
            tolerance = 0.0000001;
            n = 100;
      }
   
      //==============================================
      // Instance method for checking user's input and returning a
      // error response to the output List in the Numerical
      // Worksheet if the data is incorrect.
      //==============================================
   
      private boolean getCheck_Data()
      {
            // Instance Method Local Variables.
            String pass_string;
            String error_string1 = ("Input data format incorrect.");
            String error_string2 = ("Endpoint A needs to be less than Endpoint B.");
            String error_string3a = ("The input interval, [A,B], endpoints evaluate in the function with");
            String error_string3b = ("the same sign. Try smaller or alternate interval.");
            String error_string4 = ("The number of interations needs to larger than zero.");
      
            // Obtaining Input Data from Appropriate Panel
      
            if (!externalRoot)
            {
                  try
                  {
                       
pass_string = BisectionPanel.getData("endPointA");
               
        if (pass_string.indexOf('/') != -1)
               
           pass_string =
NA_Utils.convertFractionString(pass_string);
                       
endPointA = (Double.valueOf(pass_string)).doubleValue();
            
                       
pass_string = BisectionPanel.getData("endPointB");
                        
if (pass_string.indexOf('/') != -1)
                           
pass_string = NA_Utils.convertFractionString(pass_string);
                       
endPointB = (Double.valueOf(pass_string)).doubleValue();
            
                       
pass_string = BisectionPanel.getData("tolerance");
                        
if (pass_string.indexOf('/') != -1)
                           
pass_string = NA_Utils.convertFractionString(pass_string);
                       
tolerance = (Double.valueOf(pass_string)).doubleValue();
                       
// Determining the formatting of the output data with
                                          // dependence on tolerance. Allow for at least SSXXXX.d
                       
int pos = pass_string.index(".");
                       
decimalPlaces = pos == -1 ? 0: pass_string.substring(pos).length();
           
            colWidth =
decimalPlaces + OutputPanel.getOutputColumnSpacing();
                        
           
            pass_string =
BisectionPanel.getData("iterations");
                       
n = Integer.parseInt(pass_string);
                  }
                  catch (NumberFormatException e)
                  {
                       
OutputPanel.clearOutputData();
                       
OutputPanel.setOutputDataln(error_string1);
                       
return false;
                  }
            }
      
            // Checking Endpoint A Less Than Endpoint B.
            if (endPointA >= endPointB)
            {
                 
OutputPanel.clearOutputData();
                 
OutputPanel.setOutputDataln(error_string2);
                  return false;
            }
      
            // Checking f(A) and f(B) Opposite Sign.
            if (NA_Utils.getFunctionValue(endPointA)*
            NA_Utils.getFunctionValue(endPointB) > 0)
            {
                 
OutputPanel.clearOutputData();
                 
OutputPanel.setOutputDataln(error_string3a);
                 
OutputPanel.setOutputDataln(error_string3b);
                  return false;
            }
      
            // Checking Iterations Larger than Zero.
            if (n <= 0)
            {
                 
OutputPanel.clearOutputData();
                 
OutputPanel.setOutputDataln(error_string4);
                  return false;
            }
            return true;
      }
   
      //===============================================
      //  Processing the input data with the Bisection Algorithm
      //  to find the root. Also outputs values in the process
      //  to the List output in the Numerical Worksheet.
      //===============================================
	
      private void process_data()
      {
            // Instance Method Local Variables.
      
            double p, fa, fp, fx;
            boolean intermediateData = false;
            boolean iterationsExceeded = true;
            String error_string5 = ("Iterations completed without finding root within Tolerance.");
      
            // Determining and Setting Intermediate Data Identification.
      
            if (!externalRoot)
            {
                 
OutputPanel.clearOutputData();
                 
intermediateData = BisectionPanel.getStateCheckbox();
                  if (intermediateData)
                  {
                            // Providing some heaser information about the
                                          // intermediate data.
           
            String
colWidthSpace = "";
             
          for (int i=1; i<(colWidth-2); i++)
           
  
            
colWidthSpace = colWidthSpace + " ";
           
           
OutputPanel.setOutputDataln("   n" + colWidthSpace + "A" + 
           
       
                                                          
colWidthSpace + "B" + 
              
           
           
       
                               
colWidthSpace + "x" + 
              
           
           
       
                               
colWidthSpace + "f(x)");   
                        }
            }
      
            // Actual Algorithm for Bisection.
            //  Numerical Analsis 6th Edition 
            // By Richard L. Burden & J. Douglas Faires
            // 1997, Algorithm 2.1
      
            int i = 1;
            fa = NA_Utils.getFunctionValue(endPointA);
      
            while (i <= n)
            {
                 
p = endPointA + (endPointB-endPointA)/2;
                 
fp = NA_Utils.getFunctionValue(p);
         
                  // Test for Termination fp!=0?
                  //if ((Math.abs(p - fp) < tolerance) |
                 
//(Math.abs(p-fp)/Math.abs(p)
                 
//(Math.abs(fp) < tolerance))
         
                  // Original Algorithm Termination
                  if ((fp == 0) || ((endPointB - endPointA)/2 < tolerance))
                  {
                       
bisectionRoot = p;
                       
if (intermediateData & !externalRoot)
               
           
OutputPanel.setOutputDataln(NA_Utils.format(i, 4, 0) + 
              
               
                   
                   
   NA_Utils.format(endPointA, colWidth, decimalPlaces) + 
              
       
                                                  
NA_Utils.format(endPointB, colWidth, decimalPlaces) + 
           
       
                                                     
NA_Utils.format(p, colWidth, decimalPlaces) +
           
       
                                                     
NA_Utils.format(fp, colWidth, decimalPlaces));
                       
if (!externalRoot)
                             
OutputPanel.setOutputDataln("  Root = "+p);
                       
i = n;
                       
iterationsExceeded = false;
                  }
                  else if (intermediateData & !externalRoot)
                            OutputPanel.setOutputDataln(NA_Utils.format(i, 4, 0) + 
              
               
                   
                   
   NA_Utils.format(endPointA, colWidth, decimalPlaces) + 
              
       
                                                  
NA_Utils.format(endPointB, colWidth, decimalPlaces) + 
           
       
                                                     
NA_Utils.format(p, colWidth, decimalPlaces) +
           
       
                                                     
NA_Utils.format(fp, colWidth, decimalPlaces));
                  if (fa * fp > 0)
                  {
                       
endPointA = p;
                       
fa = fp;
                  }
                  else
                       
endPointB = p;
                  i++;
            }
      
            // Outputting Error if Iterations Completed Without
            // Finding a Root.
      
            if (iterationsExceeded & !externalRoot)
                 
OutputPanel.setOutputData(error_string5);
         
            // Misc. Format for Intermediate Data Output.
         
            if (intermediateData & !externalRoot)
                 
OutputPanel.setOutputData("");
      }
   
      //==============================================
      // Class method for an outside class to call in order to
      // obtain the root of the input equation at a specific
      // point using the Bisection algorithmn.
      //==============================================
      /**
      * A public class for the implementation of a the bisection
      * polynomial root approximation given input values of
      * type double.
      *
      * @param A Endpoint approximation less than root.
      * @param B Endpoint approximation larger than root.
      * @return Root
      */
   
      public static double getBisection_Root(double A, double B)
      {
            // Non-Standard Bisection WorkSheet Panel
            // Root Approximation.
      
            externalRoot = true;
      
            // Calling the Constructor for External
            // Root Approximation.
      
            Bisection b1 = new Bisection(A, B);
            b1.getCheck_Data();
            b1.process_data();
      
            // Return State of Bisection Class Field
            // and Root that was Found.
      
            externalRoot = false;
            return bisectionRoot;
      }
   
      //=================================================
      // Creation of the main Bisection class method to be called
      // from the Numerical Worksheet when this method is selected
      // and the execute approximation button is pressed.
      //=================================================
   
      protected static void mainBisection()
      {
            int ID = 0;
      
            Bisection b = new Bisection();
      
            if (b.getCheck_Data())
            {
                  b.process_data();
                 
OutputPanel.saveOutputData(ID);
            }
            b = null;
      }
}