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
1.4.6