zerosec.C

00001 /*
00002  * Search for a zero of a function in a given interval, by means of a
00003  *  secant method.
00004  *
00005  */
00006 
00007 /*
00008  *   Copyright (c) 1999-2001 Eric Gourgoulhon
00009  *
00010  *   This file is part of LORENE.
00011  *
00012  *   LORENE is free software; you can redistribute it and/or modify
00013  *   it under the terms of the GNU General Public License as published by
00014  *   the Free Software Foundation; either version 2 of the License, or
00015  *   (at your option) any later version.
00016  *
00017  *   LORENE is distributed in the hope that it will be useful,
00018  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
00019  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00020  *   GNU General Public License for more details.
00021  *
00022  *   You should have received a copy of the GNU General Public License
00023  *   along with LORENE; if not, write to the Free Software
00024  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00025  *
00026  */
00027 
00028 
00029 char zerosec_C[] = "$Header: /cvsroot/Lorene/C++/Source/Non_class_members/Utilities/zerosec.C,v 1.4 2002/10/16 14:37:12 j_novak Exp $" ;
00030 
00031 /*
00032  * $Id: zerosec.C,v 1.4 2002/10/16 14:37:12 j_novak Exp $
00033  * $Log: zerosec.C,v $
00034  * Revision 1.4  2002/10/16 14:37:12  j_novak
00035  * Reorganization of #include instructions of standard C++, in order to
00036  * use experimental version 3 of gcc.
00037  *
00038  * Revision 1.3  2002/04/11 09:19:46  j_novak
00039  * Back to old version of zerosec
00040  *
00041  * Revision 1.1.1.1  2001/11/20 15:19:29  e_gourgoulhon
00042  * LORENE
00043  *
00044  * Revision 1.6  2001/10/17  08:16:47  eric
00045  * In case there is not a single zero in the interval, the found
00046  * zero is displayed in the warning message.
00047  *
00048  * Revision 1.5  2000/01/04  13:20:34  eric
00049  * Test final f0 != double(0) remplace par fabs(f0) > 1.e-15 .
00050  *
00051  * Revision 1.4  1999/12/20  09:46:08  eric
00052  * Anglicisation des messages.
00053  *
00054  * Revision 1.3  1999/12/17  10:08:46  eric
00055  * Le test final fabs(f0) > 1.e-14 est remplace par f0 != 0.
00056  *
00057  * Revision 1.2  1999/12/17  09:37:40  eric
00058  * Ajout de assert(df != 0).
00059  *
00060  * Revision 1.1  1999/12/15  09:41:34  eric
00061  * Initial revision
00062  *
00063  *
00064  * $Header: /cvsroot/Lorene/C++/Source/Non_class_members/Utilities/zerosec.C,v 1.4 2002/10/16 14:37:12 j_novak Exp $
00065  *
00066  */
00067 
00068 // Headers C
00069 #include <stdlib.h>
00070 #include <math.h>
00071 #include <assert.h>
00072 
00073 // Headers Lorene 
00074 #include "headcpp.h"
00075 #include "param.h"
00076 //****************************************************************************
00077 
00078 double zerosec(double (*f)(double, const Param&), const Param& parf, 
00079     double x1, double x2, double precis, int nitermax, int& niter) {
00080     
00081     double f0_prec, f0, x0, x0_prec, dx, df ;
00082 
00083 // Teste si un zero unique existe dans l'intervalle [x_1,x_2]
00084 
00085     bool warning = false ; 
00086     
00087     f0_prec = f(x1, parf) ;
00088     f0 = f(x2, parf) ;
00089     if ( f0*f0_prec > 0.) {
00090     warning = true ; 
00091     cout << 
00092       "WARNING: zerosec: there does not exist a unique zero of the function" 
00093     << endl ;
00094     cout << "  between x1 = " << x1 << " ( f(x1)=" << f0_prec << " )" << endl ; 
00095     cout << "      and x2 = " << x2 << " ( f(x2)=" << f0 << " )" << endl ;
00096     }
00097 
00098 // Choisit la borne avec la plus petite valeur de |f(x)| comme la valeur la
00099 //  "plus recente" de x0
00100 
00101     if ( fabs(f0) < fabs(f0_prec) ) {  // On a bien choisi f0_prec et f0
00102     x0_prec = x1 ;
00103     x0 = x2 ;
00104     }
00105     else {  // il faut interchanger f0_prec et f0
00106     x0_prec = x2 ;
00107     x0 = x1 ;
00108     double swap = f0_prec ;
00109     f0_prec = f0 ;
00110     f0 = swap ; 
00111     }
00112 
00113 // Debut des iterations de la methode de la secante
00114     
00115     niter = 0 ;
00116     do {
00117     df = f0 - f0_prec ;
00118     assert(df != double(0)) ; 
00119     dx = (x0_prec - x0) * f0 / df ;
00120     x0_prec = x0 ;
00121     f0_prec = f0 ;
00122     x0 += dx ;
00123     f0 = f(x0, parf) ;
00124     niter++ ;
00125     if (niter > nitermax) {
00126         cout << "zerosec: Maximum number of iterations has been reached ! " 
00127         << endl ;
00128         abort () ;
00129     }
00130     }
00131     while ( ( fabs(dx) > precis ) && ( fabs(f0) > 1.e-15 ) ) ;
00132 
00133     if (warning) {
00134     cout << "      A zero has been found at x0 = " << x0 << endl ; 
00135     }
00136 
00137     return x0 ;
00138 }  
00139 
00140 
00141 

Generated on Tue Feb 7 01:35:21 2012 for LORENE by  doxygen 1.4.6