2
0
mirror of https://github.com/boostorg/math.git synced 2026-01-19 04:22:09 +00:00

Minor fix to previous policy update.

Lots of warning suppression.
Updated docs, and added the start of a policy tutorial.

[SVN r38415]
This commit is contained in:
John Maddock
2007-08-03 13:14:29 +00:00
parent 5622703db0
commit e2e94afe64
12 changed files with 312 additions and 47 deletions

View File

@@ -196,6 +196,8 @@ and use the function's name as the link text]
[template floorlr[x][lfloor][x][rfloor]]
[template ceil[x] '''⌈'''[x]'''⌉''']
[template header_file[file] [@../../../../[file] [file]]]
[template optional_policy[]
The final __Policy argument is optional and can be used to
control the behaviour of the function: how it handles errors,

View File

@@ -35,7 +35,232 @@ You can control policies:
[endsect][/section:pol_overview Policy Overview]
[section:pol_tutorial Policy Tutorial]
TODO??
[heading So Just What is a Policy Anyway?]
A policy is a compile-time mechanism for customising the behaviour of a
special function, or a statistical distribution. With Policies you can
control:
* What action to take when an error occurs.
* What happens when you call a function that is mathematically undefined
( for example if you ask for the mean of a Cauchy distribution).
* What happens when you ask for a quantile of a discrete distribution.
* Whether the library is allowed to internally promote `float` to `double`
and `double` to `long double` in order to improve precision.
* What precision to use when calculating the result.
Some of these policies could arguably be runtime variables, but then we couldn't
use compile-time dispatch internally to select the best evaluation method
for the given policies.
For this reason a Policy is a /type/: in fact it's an instance of the
class template `boost::math::policies::policy<>`. This class is just a
compile-time-container of user defined policies (sometimes called a typelist):
using namespace boost::math::policies;
//
// Define a policy that sets ::errno on overflow, and does
// not promote double to long double internally:
//
typedef policy<domain_error<errno_on_error>, promote_double<false> > mypolicy;
[heading Policies Have Sensible Defaults]
Most of the time you can just ignore the policy framework, the defaults for
the various policies are as follows, if these work OK for you then you can
stop reading now!
[variablelist
[[Domain Error][Throws a `std::domain_error` exception.]]
[[Pole Error][Occurs when a function is evaluated at a pole: throws a `std::domain_error` exception.]]
[[Overflow Error][Throws a `std::overflow_error` exception.]]
[[Underflow][Ignores the underflow, and returns zero.]]
[[Denormalised Result][Ignores the fact that the result is denormalised, and returns it]]
[[Internal Evaluation Error][Throws a `boost::math::evaluation_error` exception.]]
[[Promotion of float to double][Does occur by default - gives full float precision results.]]
[[Promotion of double to long double][Does occur by default if long double offers
more precision than double.]]
[[Precision of Approximation Used][By default uses an approximation that
will result in the lowest level of error for the type of the result.]]
[[Behaviour of Discrete Quantiles][Returns an integer result that is rounded
down for lower quantiles and rounded up for upper quantiles - see TODO LINK HERE!!]]
]
What's more if you define you're own policy type, then it automatically
inherits the defaults for any policies not explicitly set, so given:
using namespace boost::math::policies;
//
// Define a policy that sets ::errno on overflow, and does
// not promote double to long double internally:
//
typedef policy<domain_error<errno_on_error>, promote_double<false> > mypolicy;
then `mypolicy` defines a policy where only the overflow error handling and
`double`-promotion policies differ from the defaults.
[heading So How are Policies Used Anyway?]
The details follow later, but basically policies can be set by either:
* Defining some macros that change the default behaviour: this is the
recomended method for setting installation-wide policies.
* By instantiating a distribution object with an explicit policy:
this is mainly reserved for add-hock policy changes.
* By passing a policy to a special function as an optional final argument:
this is mainly reserved for add-hock policy changes.
* By using some helper macros to define a set of functions or distributions
in the current namespace that use a specific policy: this is the
recomended method for setting policies on a project- or translation-unit-wide
basis.
The following sections introduce these methods in more detail.
[heading Changing the Policy Defaults]
The default policies used by the library are changed by the usual
configuration macro method.
For example passing `-DBOOST_MATH_DOMAIN_ERROR_POLICY=errno_on_error` to
your compiler will cause domain errors to set `::errno` and return a NaN
rather than the usual default behaviour of throwing a `std::domain_error`
exception. There is however a very important caveat to this:
[important
[*['Default policies changed by setting configuration macros must be changed
uniformly in every translation unit in the program.]]
Failure to follow this rule may result in violations of the "one
definition rule" and result in unpredictable program behaviour.]
That means there are only two safe ways to use these macros:
* Edit them in [@../../../../boost/math/tools/user.hpp boost/math/tools/user.hpp], so that the defaults are set
on an installation-wide basis. Unfortunately this may not be convenient if
you are using a pre-installed Boost distribution (on Linux for example).
* Set the defines in your project's makefile or build environment, so that they
are set uniformly across all translation units.
What you should not do is:
* Set the defines in the source file using `#define` as doing so
almost certainly will break your program, unless you're absolutely
certain that the program is restricted to a single translation unit.
And, yes you will find examples in our test programs where we break this
rule: but only because we know they are will will always be a single
translation unit only: don't say that you weren't warned!
[heading Setting Policies for Distributions on an Ad-Hock Basis]
All of the statistical distributions in this library are class templates
that accept two template parameters, both with sensible defaults, for
example:
namespace boost{ namespace math{
template <class RealType = double, class Policy = policies::policy<> >
class fisher_f_distribution;
typedef fisher_f_distribution<> fisher_f;
}}
So if you use the shorthand-typedef for the distribution, then you get
`double` precision arithmetic and all the default policies.
However, say for example we wanted to evaluate the quantile
of the binomial distribution at float precision, without internal
promotion to double, and with the result rounded to the /nearest/
integer, then here's how it can be done:
[import ../example/policy_eg_3.cpp]
[policy_eg_3]
Which outputs:
[pre quantile is: 40]
[heading Changing the Policy on an Ad-Hock Basis for the Special Functions]
All of the special functions in this library come in two overloaded forms,
one with a final "policy" parameter, and one without. For example:
namespace boost{ namespace math{
template <class RealType, class Policy>
RealType tgamma(RealType, const Policy&);
template <class RealType>
RealType tgamma(RealType);
}} // namespaces
Normally the second version is just a forwarding wrapper to the first
like this:
template <class RealType>
inline RealType tgamma(RealType x)
{
return tgamma(x, policies::policy<>());
}
So calling a special function with a specific policy
is just a matter of defining the policy type to use
and passing it as the final parameter. For example,
suppose we want tgamma to behave in a C-compatible
fashion and set errno when an error occurs, and never
throw an exception:
[import ../example/policy_eg_1.cpp]
[policy_eg_1]
Which outputs:
[pre
Result of tgamma(30000) is: 1.#INF
errno = 34
Result of tgamma(-10) is: 1.#QNAN
errno = 33
]
Alternatively, for ad-hock use, we can use the `make_policy`
helper function to create a policy for us, this useage is more
verbose, so is probably only of use when a policy is going
to be used once only:
[import ../example/policy_eg_2.cpp]
[policy_eg_2]
[heading Setting Policies at Namespace or Translation Unit Scope]
Sometimes what you want to do is just change a set of policies within
the current scope: the one thing you should not do in this situation
is use the configuration macros, as this can lead to "One Definition
Rule" violations. Instead this library provides a pair of macros
especially for this purpose.
Let's consider the special functions first: we can declare a set of
forwarding functions that all use a specific policy using the
macro BOOST_MATH_DECLARE_SPECIAL_FUNCTIONS(['Policy]). This
macro should be used either inside a unique namespace set aside for the
purpose, or an unnamed namespace if you just want the functions
visible in global scope for the current file only.
[import ../example/policy_eg_4.cpp]
[policy_eg_4]
The same mechanism works well at file scope as well:
[import ../example/policy_eg_5.cpp]
[policy_eg_5]
[endsect][/section:pol_Tutorial Policy Tutorial]
[section:pol_ref Policy Reference]
@@ -111,7 +336,7 @@ Will return a one of the values below depending on the error type (::errno is NO
[h5 user_error]
Will call a user defined error handler: these are forward declared
in boost/math/policy/error_handling.hpp, but the actual definitions
in boost/math/policies/error_handling.hpp, but the actual definitions
must be provided by the user:
template <class T>
@@ -526,7 +751,7 @@ calculate to the maximum precision available in the type being used
- but can be set to other values to cause lower levels of precision
to be used.
namespace boost{ namespace math{ namespace policy{
namespace boost{ namespace math{ namespace policies{
template <int N>
digits10;
@@ -790,12 +1015,12 @@ with the "_distribution" suffix removed.
There's very little to say here, the `policy` class is just a rag-bag
compile-time container for a collection of policies:
```#include <boost/math/policy/policy.hpp>```
```#include <boost/math/policies/policy.hpp>```
namespace boost{
namespace math{
namespace policy
namespace policies
template <class A1 = default_policy,
class A2 = default_policy,

View File

@@ -12,7 +12,16 @@
#define BOOST_MATH_DISTRIBUTION_CONCEPT_HPP
#include <boost/math/distributions/complement.hpp>
#ifdef BOOST_MSVC
#pragma warning(push)
#pragma warning(disable: 4100)
#pragma warning(disable: 4510)
#pragma warning(disable: 4610)
#endif
#include <boost/concept_check.hpp>
#ifdef BOOST_MSVC
#pragma warning(pop)
#endif
#include <utility>
namespace boost{

View File

@@ -295,7 +295,7 @@ template <class T>
inline T raise_denorm_error(
const char* ,
const char* ,
const T& /* val */,
const T& val,
const ::boost::math::policies::denorm_error< ::boost::math::policies::errno_on_error>&)
{
errno = ERANGE;

View File

@@ -34,28 +34,33 @@ T bessel_kn(int n, T x, const Policy& pol)
return policies::raise_overflow_error<T>(function, 0, pol);
}
if (n == 0)
{
return bessel_k0(x, pol);
}
if (n == 1)
{
return bessel_k1(x, pol);
}
if (n < 0)
{
n = -n; // K_{-n}(z) = K_n(z)
}
prev = bessel_k0(x, pol);
current = bessel_k1(x, pol);
for (int k = 1; k < n; k++) // n >= 2
if (n == 0)
{
value = 2 * k * current / x + prev;
prev = current;
current = value;
value = bessel_k0(x, pol);
}
else if (n == 1)
{
value = bessel_k1(x, pol);
}
else
{
prev = bessel_k0(x, pol);
current = bessel_k1(x, pol);
int k = 1;
BOOST_ASSERT(k < n);
do
{
value = 2 * k * current / x + prev;
prev = current;
current = value;
++k;
}
while(k < n);
}
return value;
}

View File

@@ -34,14 +34,9 @@ T bessel_yn(int n, T x, const Policy& pol)
"Got x = %1%, but x must be > 0, complex result not supported.", x, pol);
}
if (n == 0)
{
return bessel_y0(x, pol);
}
if (n == 1)
{
return bessel_y1(x, pol);
}
//
// Reflection comes first:
//
if (n < 0)
{
factor = (n & 0x1) ? -1 : 1; // Y_{-n}(z) = (-1)^n Y_n(z)
@@ -52,16 +47,30 @@ T bessel_yn(int n, T x, const Policy& pol)
factor = 1;
}
prev = bessel_y0(x, pol);
current = bessel_y1(x, pol);
for (int k = 1; k < n; k++) // n >= 2
if (n == 0)
{
value = 2 * k * current / x - prev;
prev = current;
current = value;
value = bessel_y0(x, pol);
}
else if (n == 1)
{
value = factor * bessel_y1(x, pol);
}
else
{
prev = bessel_y0(x, pol);
current = bessel_y1(x, pol);
int k = 1;
BOOST_ASSERT(k < n);
do
{
value = 2 * k * current / x - prev;
prev = current;
current = value;
++k;
}
while(k < n);
value *= factor;
}
value *= factor;
return value;
}

View File

@@ -58,8 +58,9 @@ T ellint_rc_imp(T x, T y, const Policy& pol)
else
prefix = 1;
// duplication
for (k = 1; k < BOOST_MATH_MAX_ITER; k++)
// duplication:
k = 1;
do
{
u = (x + y + y) / 3;
S = y / u - 1; // 1 - x / u = 2 * S
@@ -72,7 +73,8 @@ T ellint_rc_imp(T x, T y, const Policy& pol)
lambda = 2 * sx * sy + y;
x = (x + lambda) / 4;
y = (y + lambda) / 4;
}
++k;
}while(k < BOOST_MATH_MAX_ITER);
// Check to see if we gave up too soon:
policies::check_series_iterations(function, k, pol);

View File

@@ -60,7 +60,8 @@ T ellint_rd_imp(T x, T y, T z, const Policy& pol)
// duplication
sigma = 0;
factor = 1;
for (k = 1; k < BOOST_MATH_MAX_ITER; k++)
k = 1;
do
{
u = (x + y + z + z + z) / 5;
X = (u - x) / u;
@@ -77,7 +78,10 @@ T ellint_rd_imp(T x, T y, T z, const Policy& pol)
x = (x + lambda) / 4;
y = (y + lambda) / 4;
z = (z + lambda) / 4;
++k;
}
while(k < BOOST_MATH_MAX_ITER);
// Check to see if we gave up too soon:
policies::check_series_iterations(function, k, pol);

View File

@@ -64,7 +64,8 @@ T ellint_rf_imp(T x, T y, T z, const Policy& pol)
}
// duplication
for (k = 1; k < BOOST_MATH_MAX_ITER; k++)
k = 1;
do
{
u = (x + y + z) / 3;
X = (u - x) / u;
@@ -82,7 +83,10 @@ T ellint_rf_imp(T x, T y, T z, const Policy& pol)
x = (x + lambda) / 4;
y = (y + lambda) / 4;
z = (z + lambda) / 4;
++k;
}
while(k < BOOST_MATH_MAX_ITER);
// Check to see if we gave up too soon:
policies::check_series_iterations(function, k, pol);
BOOST_MATH_INSTRUMENT_CODE(k);

View File

@@ -98,7 +98,8 @@ T ellint_rj_imp(T x, T y, T z, T p, const Policy& pol)
// duplication
sigma = 0;
factor = 1;
for (k = 1; k < BOOST_MATH_MAX_ITER; k++)
k = 1;
do
{
u = (x + y + z + p + p) / 5;
X = (u - x) / u;
@@ -123,7 +124,10 @@ T ellint_rj_imp(T x, T y, T z, T p, const Policy& pol)
y = (y + lambda) / 4;
z = (z + lambda) / 4;
p = (p + lambda) / 4;
++k;
}
while(k < BOOST_MATH_MAX_ITER);
// Check to see if we gave up too soon:
policies::check_series_iterations(function, k, pol);

View File

@@ -13,9 +13,9 @@ project
<toolset>darwin:<cxxflags>-Wno-missing-braces
<toolset>acc:<cxxflags>+W2068,2461,2236,4070
<toolset>intel:<cxxflags>-Qwd264,239
<toolset>msvc:<cxxflags>/EHa
<toolset>msvc:<warnings>all
<toolset>msvc:<asynch-exceptions>on
<toolset>msvc:<cxxflags>/wd4996
<toolset>msvc:<cxxflags>/W4
<toolset>msvc:<cxxflags>/wd4512
<toolset>msvc:<cxxflags>/wd4610
<toolset>msvc:<cxxflags>/wd4510
@@ -182,3 +182,4 @@ compile compile_test/tools_toms748_solve_inc_test.cpp ;

View File

@@ -7,7 +7,7 @@
extern void other_test();
int main(int argc, char* argv[])
int main(int argc, char* [])
{
if(argc > 10000)
{