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:
@@ -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,
|
||||
|
||||
235
doc/policy.qbk
235
doc/policy.qbk
@@ -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,
|
||||
|
||||
@@ -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{
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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 ;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
extern void other_test();
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
int main(int argc, char* [])
|
||||
{
|
||||
if(argc > 10000)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user