Boost logo

Boost-Commit :

From: john_at_[hidden]
Date: 2007-08-08 06:48:17


Author: johnmaddock
Date: 2007-08-08 06:48:10 EDT (Wed, 08 Aug 2007)
New Revision: 38504
URL: http://svn.boost.org/trac/boost/changeset/38504

Log:
More or less finished policy tutorial.
Trivial whitespace change to test_negative_binomial.cpp.
Added:
   sandbox/math_toolkit/libs/math/example/policy_eg_8.cpp (contents, props changed)
   sandbox/math_toolkit/libs/math/example/policy_eg_9.cpp (contents, props changed)
Text files modified:
   sandbox/math_toolkit/libs/math/doc/policy.qbk | 10 ++++++++++
   sandbox/math_toolkit/libs/math/test/test_negative_binomial.cpp | 2 +-
   2 files changed, 11 insertions(+), 1 deletions(-)

Modified: sandbox/math_toolkit/libs/math/doc/policy.qbk
==============================================================================
--- sandbox/math_toolkit/libs/math/doc/policy.qbk (original)
+++ sandbox/math_toolkit/libs/math/doc/policy.qbk 2007-08-08 06:48:10 EDT (Wed, 08 Aug 2007)
@@ -292,6 +292,16 @@
 
 [policy_eg_7]
 
+[heading Calling User Defined Error Handlers]
+
+[import ../example/policy_eg_8.cpp]
+
+[policy_eg_8]
+
+[import ../example/policy_eg_9.cpp]
+
+[policy_eg_9]
+
 [endsect][/section:pol_Tutorial Policy Tutorial]
 
 [section:pol_ref Policy Reference]

Added: sandbox/math_toolkit/libs/math/example/policy_eg_8.cpp
==============================================================================
--- (empty file)
+++ sandbox/math_toolkit/libs/math/example/policy_eg_8.cpp 2007-08-08 06:48:10 EDT (Wed, 08 Aug 2007)
@@ -0,0 +1,129 @@
+// Copyright John Maddock 2007.
+// Use, modification and distribution are subject to the
+// Boost Software License, Version 1.0. (See accompanying file
+// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+// Note that this file contains quickbook markup as well as code
+// and comments, don't change any of the special comment markups!
+
+#include <iostream>
+
+//[policy_eg_8
+
+/*`
+
+Suppose we want our own user-defined error handlers rather than the
+any of the default ones supplied by the libary to be used. If
+we set the policy for a specific type of error to `user_error`
+then the library will call a user-supplied error handler.
+These are forward declared, but not defined in
+boost/math/policy/error_handling.hpp like this:
+
+ namespace boost{ namespace math{ namespace policy{
+
+ template <class T>
+ T user_domain_error(const char* function, const char* message, const T& val);
+ template <class T>
+ T user_pole_error(const char* function, const char* message, const T& val);
+ template <class T>
+ T user_overflow_error(const char* function, const char* message, const T& val);
+ template <class T>
+ T user_underflow_error(const char* function, const char* message, const T& val);
+ template <class T>
+ T user_denorm_error(const char* function, const char* message, const T& val);
+ template <class T>
+ T user_evaluation_error(const char* function, const char* message, const T& val);
+
+ }}} // namespaces
+
+So out first job is to include the header we want to use, and then
+provide definitions for the user-defined error handlers we want to use:
+
+*/
+
+#include <iostream>
+#include <boost/math/special_functions.hpp>
+
+namespace boost{ namespace math{ namespace policies{
+
+template <class T>
+T user_domain_error(const char* function, const char* message, const T& val)
+{
+ std::cerr << "Domain Error." << std::endl;
+ return std::numeric_limits<T>::quiet_NaN();
+}
+
+template <class T>
+T user_pole_error(const char* function, const char* message, const T& val)
+{
+ std::cerr << "Pole Error." << std::endl;
+ return std::numeric_limits<T>::quiet_NaN();
+}
+
+
+}}} // namespaces
+
+
+/*`
+
+Now we'll need to define a suitable policy that will call these handlers,
+and define some forwarding functions that make use of the policy:
+
+*/
+
+namespace{
+
+using namespace boost::math::policies;
+
+typedef policy<
+ domain_error<user_error>,
+ pole_error<user_error>
+> user_error_policy;
+
+BOOST_MATH_DECLARE_SPECIAL_FUNCTIONS(user_error_policy)
+
+} // close unnamed namespace
+
+/*`
+
+We now have a set of forwarding functions defined in an unnamed namespace
+that all look something like this:
+
+``
+template <class RealType>
+inline typename boost::math::tools::promote_args<RT>::type
+ tgamma(RT z)
+{
+ return boost::math::tgamma(z, c_policy());
+}
+``
+
+So that when we call `tgamma(z)` we really end up calling
+`boost::math::tgamma(z, user_error_policy())`, and any
+errors will get directed to our own error handlers:
+
+*/
+
+
+int main()
+{
+ std::cout << "Result of erf_inv(-10) is: "
+ << erf_inv(-10) << std::endl;
+ std::cout << "Result of tgamma(-10) is: "
+ << tgamma(-10) << std::endl;
+}
+
+/*`
+
+Which outputs:
+
+[pre
+Domain Error.
+Result of erf_inv(-10) is: 1.#QNAN
+Pole Error.
+Result of tgamma(-10) is: 1.#QNAN
+]
+*/
+
+//]
+

Added: sandbox/math_toolkit/libs/math/example/policy_eg_9.cpp
==============================================================================
--- (empty file)
+++ sandbox/math_toolkit/libs/math/example/policy_eg_9.cpp 2007-08-08 06:48:10 EDT (Wed, 08 Aug 2007)
@@ -0,0 +1,316 @@
+// Copyright John Maddock 2007.
+// Use, modification and distribution are subject to the
+// Boost Software License, Version 1.0. (See accompanying file
+// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+// Note that this file contains quickbook markup as well as code
+// and comments, don't change any of the special comment markups!
+
+#include <iostream>
+
+//[policy_eg_9
+
+/*`
+
+The previous example was all well and good, but the custom error handlers
+didn't really do much of any use. In this example we'll implement all
+the custom handlers and show how the information provided to them can be
+used to generate nice formatted error messages.
+
+Each error handler has the general form:
+
+ template <class T>
+ T user_``['error_type]``(
+ const char* function,
+ const char* message,
+ const T& val);
+
+and accepts three arguments:
+
+[variablelist
+[[const char* function]
+ [The name of the function that raised the error, this string
+ contains one or more %1% format specifiers that should be
+ replaced by the name of type T.]]
+[[const char* message]
+ [A message associated with the error, normally this
+ contains a %1% format specifier that should be replaced with
+ the value of ['value]: however note that overflow and underflow messages
+ do not contain this %1% specifier (since the value of ['value] is
+ immaterial in these cases).]]
+[[const T& value]
+ [The value that caused the error: either an argument to the function
+ if this is a domain or pole error, the tentative result
+ if this is a denorm or evaluation error, or zero or infinity for
+ underflow or overflow errors.]]
+]
+
+As before we'll include the headers we need first:
+
+*/
+
+#include <iostream>
+#include <boost/math/special_functions.hpp>
+
+/*`
+
+Next we'll implement the error handlers for each type of error,
+starting with domain errors:
+
+*/
+
+namespace boost{ namespace math{ namespace policies{
+
+template <class T>
+T user_domain_error(const char* function, const char* message, const T& val)
+{
+ /*`
+ We'll begin with a bit of defensive programming:
+ */
+ if(function == 0)
+ function = "Unknown function with arguments of type %1%";
+ if(message == 0)
+ message = "Cause unknown with bad argument %1%";
+ /*`
+ Next we'll format the name of the function with the name of type T:
+ */
+ std::string msg("Error in function ");
+ msg += (boost::format(function) % typeid(T).name()).str();
+ /*`
+ Then likewise format the error message with the value of parameter /val/,
+ making sure we output all the digits of /val/:
+ */
+ msg += ": \n";
+ int prec = 2 + (std::numeric_limits<T>::digits * 30103UL) / 100000UL;
+ msg += (boost::format(message) % boost::io::group(std::setprecision(prec), val)).str();
+ /*
+ Now we just have to do something with the message, we could throw an
+ exception, but for the purposes of this example we'll just dump the message
+ to std::cerr:
+ */
+ std::cerr << msg << std::endl;
+ /*
+ Finally the only sensible value we can return from a domain error is a NaN:
+ */
+ return std::numeric_limits<T>::quiet_NaN();
+}
+
+/*`
+Pole errors are essentially a special case of domain errors,
+so in this example we'll just return the result of a domain error:
+*/
+
+template <class T>
+T user_pole_error(const char* function, const char* message, const T& val)
+{
+ return user_domain_error(function, message, val);
+}
+
+/*`
+Overflow errors are very similar to domain errors, except that there's
+no %1% format specifier in the /message/ parameter:
+*/
+template <class T>
+T user_overflow_error(const char* function, const char* message, const T& val)
+{
+ if(function == 0)
+ function = "Unknown function with arguments of type %1%";
+ if(message == 0)
+ message = "Result of function is too large to represent";
+
+ std::string msg("Error in function ");
+ msg += (boost::format(function) % typeid(T).name()).str();
+
+ msg += ": \n";
+ msg += message;
+
+ std::cerr << msg << std::endl;
+
+ // Value passed to the function is an infinity, just return it:
+ return val;
+}
+
+/*`
+Underflow errors are much the same as overflow:
+*/
+
+template <class T>
+T user_underflow_error(const char* function, const char* message, const T& val)
+{
+ if(function == 0)
+ function = "Unknown function with arguments of type %1%";
+ if(message == 0)
+ message = "Result of function is too small to represent";
+
+ std::string msg("Error in function ");
+ msg += (boost::format(function) % typeid(T).name()).str();
+
+ msg += ": \n";
+ msg += message;
+
+ std::cerr << msg << std::endl;
+
+ // Value passed to the function is zero, just return it:
+ return val;
+}
+
+/*`
+Denormalised results are much the same as underflow:
+*/
+
+template <class T>
+T user_denorm_error(const char* function, const char* message, const T& val)
+{
+ if(function == 0)
+ function = "Unknown function with arguments of type %1%";
+ if(message == 0)
+ message = "Result of function is denormalised";
+
+ std::string msg("Error in function ");
+ msg += (boost::format(function) % typeid(T).name()).str();
+
+ msg += ": \n";
+ msg += message;
+
+ std::cerr << msg << std::endl;
+
+ // Value passed to the function is denormalised, just return it:
+ return val;
+}
+
+/*`
+Which leaves us with evaluation errors, these occur when an internal
+error occurs that prevents the function being fully evaluated.
+The parameter /val/ contains the closest approximation to the result
+found so far:
+*/
+
+template <class T>
+T user_evaluation_error(const char* function, const char* message, const T& val)
+{
+ if(function == 0)
+ function = "Unknown function with arguments of type %1%";
+ if(message == 0)
+ message = "An internal evaluation error occured with "
+ "the best value calculated so far of %1%";
+
+ std::string msg("Error in function ");
+ msg += (boost::format(function) % typeid(T).name()).str();
+
+ msg += ": \n";
+ int prec = 2 + (std::numeric_limits<T>::digits * 30103UL) / 100000UL;
+ msg += (boost::format(message) % boost::io::group(std::setprecision(prec), val)).str();
+
+ std::cerr << msg << std::endl;
+
+ // What do we return here? This is generally a fatal error,
+ // that should never occur, just return a NaN for the purposes
+ // of the example:
+ return std::numeric_limits<T>::quiet_NaN();
+}
+
+}}} // namespaces
+
+
+/*`
+
+Now we'll need to define a suitable policy that will call these handlers,
+and define some forwarding functions that make use of the policy:
+
+*/
+
+namespace{
+
+using namespace boost::math::policies;
+
+typedef policy<
+ domain_error<user_error>,
+ pole_error<user_error>,
+ overflow_error<user_error>,
+ underflow_error<user_error>,
+ denorm_error<user_error>,
+ evaluation_error<user_error>
+> user_error_policy;
+
+BOOST_MATH_DECLARE_SPECIAL_FUNCTIONS(user_error_policy)
+
+} // close unnamed namespace
+
+/*`
+
+We now have a set of forwarding functions defined in an unnamed namespace
+that all look something like this:
+
+``
+template <class RealType>
+inline typename boost::math::tools::promote_args<RT>::type
+ tgamma(RT z)
+{
+ return boost::math::tgamma(z, c_policy());
+}
+``
+
+So that when we call `tgamma(z)` we really end up calling
+`boost::math::tgamma(z, user_error_policy())`, and any
+errors will get directed to our own error handlers:
+
+*/
+
+
+int main()
+{
+ // Raise a domain error:
+ std::cout << "Result of erf_inv(-10) is: "
+ << erf_inv(-10) << std::endl << std::endl;
+ // Raise a pole error:
+ std::cout << "Result of tgamma(-10) is: "
+ << tgamma(-10) << std::endl << std::endl;
+ // Raise an overflow error:
+ std::cout << "Result of tgamma(3000) is: "
+ << tgamma(3000) << std::endl << std::endl;
+ // Raise an underflow error:
+ std::cout << "Result of tgamma(-190.5) is: "
+ << tgamma(-190.5) << std::endl << std::endl;
+ // Unfortunately we can't predicably raise a denormalised
+ // result, nor can we raise an evaluation error in this example
+ // since these should never really occur!
+}
+
+/*`
+
+Which outputs:
+
+[pre
+Error in function boost::math::erf_inv<double>(double, double):
+Argument outside range \[-1, 1\] in inverse erf function (got p=-10).
+Result of erf_inv(-10) is: 1.#QNAN
+
+Error in function boost::math::tgamma<long double>(long double):
+Evaluation of tgamma at a negative integer -10.
+Result of tgamma(-10) is: 1.#QNAN
+
+Error in function boost::math::tgamma<long double>(long double):
+Result of tgamma is too large to represent.
+Error in function boost::math::tgamma<double>(double):
+Result of function is too large to represent
+Result of tgamma(3000) is: 1.#INF
+
+Error in function boost::math::tgamma<long double>(long double):
+Result of tgamma is too large to represent.
+Error in function boost::math::tgamma<long double>(long double):
+Result of tgamma is too small to represent.
+Result of tgamma(-190.5) is: 0
+]
+
+Notice how some of the calls result in an error handler being called more
+than once, or for more than one handler to be called: this is an artifact
+of the fact that many functions are implemented in terms of one or more
+sub-routines each of which may have it's own error handling. For example
+tgamma(-190.5) is implemented in terms of tgamma(190.5) - which overflows -
+the reflection formula for tgamma then notices that it's dividing by
+infinity and underflows.
+
+*/
+
+//]
+

Modified: sandbox/math_toolkit/libs/math/test/test_negative_binomial.cpp
==============================================================================
--- sandbox/math_toolkit/libs/math/test/test_negative_binomial.cpp (original)
+++ sandbox/math_toolkit/libs/math/test/test_negative_binomial.cpp 2007-08-08 06:48:10 EDT (Wed, 08 Aug 2007)
@@ -48,7 +48,7 @@
                RealType Q, // Complement of CDF.
                RealType tol) // Test tolerance.
 {
- boost::math::negative_binomial_distribution<RealType> bn(N, p);
+ boost::math::negative_binomial_distribution<RealType> bn(N, p);
    BOOST_CHECK_EQUAL(N, bn.successes());
    BOOST_CHECK_EQUAL(p, bn.success_fraction());
    BOOST_CHECK_CLOSE(


Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk