From 697517dcb15f53d0f7b3c596911b2d0ac5195140 Mon Sep 17 00:00:00 2001 From: Wolfgang Bangerth Date: Thu, 16 Aug 2018 11:32:53 -0600 Subject: [PATCH] Document a problem with the FunctionParser class. --- include/deal.II/base/function_parser.h | 47 +++++++++++++++++++------- 1 file changed, 35 insertions(+), 12 deletions(-) diff --git a/include/deal.II/base/function_parser.h b/include/deal.II/base/function_parser.h index 7ca57c491d..31de68488f 100644 --- a/include/deal.II/base/function_parser.h +++ b/include/deal.II/base/function_parser.h @@ -55,14 +55,36 @@ class Vector; * sin, cos, tan, asin, acos, atan, sinh, cosh, tanh, asinh, acosh, atanh, * atan2, log2, log10, log, ln, exp, sqrt, sign, rint, abs, min, max, sum, avg * @endcode - * this class also supports: - * - if(condition, then-value, else-value) - * - | and & (logic or and and) - * - int(x), ceil(x), floor(x) (rounding) - * - cot(x), csc(x), sec(x) - * - pow(x,n), log(x) - * - erfc(x) - * - rand(), rand_seed(seed) + * this class also supports the following operations: + * - if(condition, then-value, else-value) + * - | and & (logic or and and) + * - int(x), ceil(x), floor(x) (rounding) + * - cot(x), csc(x), sec(x) + * - pow(x,n), log(x) + * - erfc(x) + * - rand(), rand_seed(seed) + * + * @note This class implements the list of functions just mentioned as + * user-defined functions by extending muparser. This means, in particular, + * that the `if(condition, then-value, else-value)` syntax evaluates all + * three arguments before determining whether the condition is true, and + * then discarding either the "then" or the "else" expressions. In almost + * all situations, this is not a problem except if the evaluation of + * one of the expressions throws a floating point exception in cases + * where it will later be discarded. (Assuming floating point exceptions + * are switched on, as is the default for deal.II in debug mode on most + * systems.) An example would be the expression `if(x>0, sqrt(x), 0)` + * which is mathematically well defined, but on systems where this is + * enabled will abort the program with a floating point exception when + * evaluated with a negative `x`. This is because the square root of + * `x` is computed before the `if` statement's condition is considered + * to determine whether the result should be the second or third + * argument. If this kind of behavior is a problem, you can resort to + * the muparser built-in syntax `(condition ? then-value : else-value)`, + * using the ternary syntax familiar to C++ programmers. If this + * syntax is used, muparser uses lazy evaluation in which only one of the + * branches is evaluated, depending on whether the `condition` is + * true or false. * * The following examples shows how to use this class: * @code @@ -249,8 +271,8 @@ public: * component of the point in which the function is evaluated, the second * variable to the second component and so forth. If this function is also * time dependent, then it is necessary to specify it by setting the - * time_dependent parameter to true. An exception is thrown if the - * number of variables specified here is different from dim (if this + * time_dependent parameter to true. An exception is thrown if + * the number of variables specified here is different from dim (if this * function is not time-dependent) or from dim+1 (if it is time- dependent). * * expressions: a list of strings containing the expressions that @@ -264,7 +286,7 @@ public: * number pi). An expression is valid if and only if it contains only * defined variables and defined constants (other than the functions * specified above). If a constant is given whose name is not valid (eg: - * constants["sin"] = 1.5;) an exception is thrown. + * constants["sin"] = 1.5;) an exception is thrown. * * time_dependent. If this is a time dependent function, then the * last variable declared in vars is assumed to be the time variable, @@ -313,7 +335,8 @@ public: * Return all components of a vector-valued function at the given point @p * p. * - * values shall have the right size beforehand, i.e. #n_components. + * values shall have the right size beforehand, i.e. + * #n_components. */ virtual void vector_value(const Point &p, Vector &values) const override; -- 2.39.5