private static void Main() //****************************************************************************80 // // Purpose: // // MAIN is the main program for TOMS743_TEST. // // Licensing: // // This code is distributed under the GNU LGPL license. // // Modified: // // 17 June 2014 // // Author: // // Original FORTRAN77 version by Andrew Barry, S. J. Barry, // Patricia Culligan-Hensley. // C++ version by John Burkardt. // // Reference: // // Andrew Barry, S. J. Barry, Patricia Culligan-Hensley, // Algorithm 743: WAPR - A Fortran routine for calculating real // values of the W-function, // ACM Transactions on Mathematical Software, // Volume 21, Number 2, June 1995, pages 172-181. // { Console.WriteLine(""); Console.WriteLine("TOMS743_TEST"); Console.WriteLine(" Test the TOMS743 library."); int nbits = NBITS.nbits_compute(); Console.WriteLine(""); Console.WriteLine(" Number of bits in mantissa - 1 = " + nbits + ""); test01(nbits); const double dx = +1.0E-09; int n = 10; test02(nbits, dx, n); const double xmin = 0.0; const double xmax = 1.0E+20; n = 20; test03(nbits, xmin, xmax, n); Console.WriteLine(""); Console.WriteLine("TOMS743_TEST"); Console.WriteLine(" Normal end of execution."); Console.WriteLine(""); }
public static double wapr(ref WAPRData data, double x, int nb, ref int nerror, int l) //****************************************************************************80 // // WAPR approximates the W function. // // Discussion: // // The call will fail if the input value X is out of range. // The range requirement for the upper branch is: // -Math.Exp(-1) <= X. // The range requirement for the lower branch is: // -Math.Exp(-1) < X < 0. // // Licensing: // // This code is distributed under the GNU LGPL license. // // Modified: // // 17 June 2014 // // Author: // // Original FORTRAN77 version by Andrew Barry, S. J. Barry, // Patricia Culligan-Hensley. // C++ version by John Burkardt. // // Reference: // // Andrew Barry, S. J. Barry, Patricia Culligan-Hensley, // Algorithm 743: WAPR - A Fortran routine for calculating real // values of the W-function, // ACM Transactions on Mathematical Software, // Volume 21, Number 2, June 1995, pages 172-181. // // Parameters: // // Input, double X, the argument. // // Input, int NB, indicates the desired branch. // * 0, the upper branch; // * nonzero, the lower branch. // // Output, int &NERROR, the error flag. // * 0, successful call. // * 1, failure, the input X is out of range. // // Input, int L, indicates the interpretation of X. // * 1, X is actually the offset from -(Math.Exp-1), so compute W(X-Math.Exp(-1)). // * not 1, X is the argument; compute W(X); // // Output, double WAPR, the approximate value of W(X). // { double delx; int i; double reta; double xx; double zl; double value = 0.0; nerror = 0; switch (data.init) { case 0: { data.init = 1; data.nbits = NBITS.nbits_compute(); data.niter = data.nbits switch { >= 56 => 2, _ => data.niter }; // // Various mathematical constants. // data.em = -Math.Exp(-1.0); data.em9 = -Math.Exp(-9.0); data.c13 = 1.0 / 3.0; data.c23 = 2.0 * data.c13; data.em2 = 2.0 / data.em; data.d12 = -data.em2; data.tb = Math.Pow(0.5, data.nbits); data.x0 = Math.Pow(data.tb, 1.0 / 6.0) * 0.5; data.x1 = (1.0 - 17.0 * Math.Pow(data.tb, 2.0 / 7.0)) * data.em; data.an3 = 8.0 / 3.0; data.an4 = 135.0 / 83.0; data.an5 = 166.0 / 39.0; data.an6 = 3167.0 / 3549.0; data.s2 = Math.Sqrt(2.0); data.s21 = 2.0 * data.s2 - 3.0; data.s22 = 4.0 - 3.0 * data.s2; data.s23 = data.s2 - 2.0; break; }
public static double bisect(ref BisectData data, double xx, int nb, ref int ner, int l) //****************************************************************************80 // // Purpose: // // BISECT approximates the W function using bisection. // // Discussion: // // The parameter TOL, which determines the accuracy of the bisection // method, is calculated using NBITS (assuming the final bit is lost // due to rounding error). // // N0 is the maximum number of iterations used in the bisection // method. // // For XX close to 0 for Wp, the exponential approximation is used. // The approximation is exact to O(XX^8) so, depending on the value // of NBITS, the range of application of this formula varies. Outside // this range, the usual bisection method is used. // // Licensing: // // This code is distributed under the GNU LGPL license. // // Modified: // // 17 June 2014 // // Author: // // Original FORTRAN77 version by Andrew Barry, S. J. Barry, // Patricia Culligan-Hensley. // C++ version by John Burkardt. // // Reference: // // Andrew Barry, S. J. Barry, Patricia Culligan-Hensley, // Algorithm 743: WAPR - A Fortran routine for calculating real // values of the W-function, // ACM Transactions on Mathematical Software, // Volume 21, Number 2, June 1995, pages 172-181. // // Parameters: // // Input, double XX, the argument. // // Input, int NB, indicates the branch of the W function. // 0, the upper branch; // nonzero, the lower branch. // // Output, int &NER, the error flag. // 0, success; // 1, the routine did not converge. Perhaps reduce NBITS and try again. // // Input, int L, the offset indicator. // 1, XX represents the offset of the argument from -Math.Exp(-1). // not 1, XX is the actual argument. // // Output, double BISECT, the value of W(X), as determined // { double d; double f; double fd; int i; const int n0 = 500; double r; double tol; double u; double value = 0.0; ner = 0; data.nbits = data.nbits switch { 0 => NBITS.nbits_compute(), _ => data.nbits }; double x = l switch { 1 => xx - Math.Exp(-1.0), _ => xx }; switch (nb) { case 0: { double test = 1.0 / Math.Pow(Math.Pow(2.0, data.nbits), 1.0 / 7.0); if (Math.Abs(x) < test) { value = x * Math.Exp(-x * Math.Exp(-x * Math.Exp(-x * Math.Exp(-x * Math.Exp(-x * Math.Exp(-x)))))); return(value); } u = Crude.crude(ref data.data, x, nb) + 1.0E-03; tol = Math.Abs(u) / Math.Pow(2.0, data.nbits); d = Math.Max(u - 2.0E-03, -1.0); for (i = 1; i <= n0; i++) { r = 0.5 * (u - d); value = d + r; // // Find root using w*Math.Exp(w)-x to avoid ln(0) error. // if (x < Math.Exp(1.0)) { f = value * Math.Exp(value) - x; fd = d * Math.Exp(d) - x; } // // Find root using ln(w/x)+w to avoid overflow error. // else { f = Math.Log(value / x) + value; fd = Math.Log(d / x) + d; } switch (f) { case 0.0: return(value); } if (Math.Abs(r) <= tol) { return(value); } switch (fd * f) { case > 0.0: d = value; break; default: u = value; break; } } break; } default: { d = Crude.crude(ref data.data, x, nb) - 1.0E-03; u = Math.Min(d + 2.0E-03, -1.0); tol = Math.Abs(u) / Math.Pow(2.0, data.nbits); for (i = 1; i <= n0; i++) { r = 0.5 * (u - d); value = d + r; f = value * Math.Exp(value) - x; switch (f) { case 0.0: return(value); } if (Math.Abs(r) <= tol) { return(value); } fd = d * Math.Exp(d) - x; switch (fd * f) { case > 0.0: d = value; break; default: u = value; break; } } break; } } // // The iteration did not converge. // ner = 1; return(value); } }