📄 policy_tutorial.qbk
字号:
[section:pol_tutorial Policy Tutorial][section:what_is_a_policy 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 cancontrol:* 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'tuse compile-time dispatch internally to select the best evaluation methodfor 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-selected policies (sometimes called a type-list): 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;[endsect][/section:what_is_a_policy So Just What is a Policy Anyway?][section:policy_tut_defaults 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 canstop 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.]][[Rounding Error][Throws a `boost::math::rounding_error` exception.]][[Internal Evaluation Error][Throws a `boost::math::evaluation_error` exception.]][[Indeterminate Result Error][Returns a result that depends on the function where the error occurred.]][[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] [ The quantile function will by default return an integer result that has been /rounded outwards/. That is to say lower quantiles (where the probability is less than 0.5) are rounded downward, and upper quantiles (where the probability is greater than 0.5) are rounded upwards. This behaviour ensures that if an X% quantile is requested, then /at least/ the requested coverage will be present in the central region, and /no more than/ the requested coverage will be present in the tails.This behaviour can be changed so that the quantile functions are rounded differently, or even return a real-valued result using [link math_toolkit.policy.pol_overview Policies]. It is strongly recommended that you read the tutorial [link math_toolkit.policy.pol_tutorial.understand_dis_quant Understanding Quantiles of Discrete Distributions] before using the quantile function on a discrete distribution. The [link math_toolkit.policy.pol_ref.discrete_quant_ref reference docs] describe how to change the rounding policy for these distributions.]]]What's more, if you define your own policy type, then it automaticallyinherits 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.[endsect][/section:policy_tut_defaults Policies Have Sensible Defaults][section:policy_usage 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 recommended method for setting installation-wide policies].* By instantiating a distribution object with an explicit policy: this is mainly reserved for ad hoc policy changes.* By passing a policy to a special function as an optional final argument: this is mainly reserved for ad hoc policy changes.* By using some helper macros to define a set of functions or distributionsin the current namespace that use a specific policy: [*this is therecommended method for setting policies on a project- or translation-unit-widebasis].The following sections introduce these methods in more detail.[endsect][/section:policy_usage So How are Policies Used Anyway?][section:changing_policy_defaults Changing the Policy Defaults]The default policies used by the library are changed by the usualconfiguration macro method.For example, passing `-DBOOST_MATH_DOMAIN_ERROR_POLICY=errno_on_error` toyour compiler will cause domain errors to set `::errno` and return a NaNrather than the usual default behaviour of throwing a `std::domain_error`exception.[tip For Microsoft Visual Studio,you can add to the Project Property Page,C/C++, Preprocessor, Preprocessor definitions like:``BOOST_MATH_ASSERT_UNDEFINED_POLICY=0BOOST_MATH_OVERFLOW_ERROR_POLICY=errno_on_error``This may be helpful to avoid complications with pre-compiled headersthat may mean that the equivalent definitions in source code:``#define BOOST_MATH_ASSERT_UNDEFINED_POLICY false#define BOOST_MATH_OVERFLOW_ERROR_POLICY errno_on_error`` may be ignored.The compiler command line shows:``/D "BOOST_MATH_ASSERT_UNDEFINED_POLICY=0"/D "BOOST_MATH_OVERFLOW_ERROR_POLICY=errno_on_error"``] [/MSVC tip]There is however a very important caveat to this:[important[*['Default policies changed by setting configuration macros must be changeduniformly in every translation unit in the program.]] Failure to follow this rule may result in violations of the "OneDefinition Rule (ODR)" 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 ifyou are using a pre-installed Boost distribution (on Linux for example).* Set the defines in your project's Makefile or build environment, so that theyare set uniformly across all translation units.What you should *not* do is:* Set the defines in the source file using `#define` as doing soalmost certainly will break your program, unless you're absolutelycertain that the program is restricted to a single translation unit.And, yes, you will find examples in our test programs where we break thisrule: but only because we know there will always be a singletranslation unit only: ['don't say that you weren't warned!][error_handling_example][endsect][/section:changing_policy_defaults Changing the Policy Defaults][section:ad_hoc_dist_policies Setting Policies for Distributions on an Ad Hoc Basis]All of the statistical distributions in this library are class templatesthat accept two template parameters, both with sensible defaults, forexample: namespace boost{ namespace math{ template <class RealType = double, class Policy = policies::policy<> > class fisher_f_distribution; typedef fisher_f_distribution<> fisher_f; }} This policy gets used by all the accessor functions that accepta distribution as an argument, and forwarded to all the functions calledby these. 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 quantileof the binomial distribution at float precision, without internalpromotion 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][endsect][/section:ad_hoc_dist_policies Setting Policies for Distributions on an Ad Hoc Basis][section:ad_hoc_sf_policies Changing the Policy on an Ad Hoc 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 firstlike this: template <class RealType> inline RealType tgamma(RealType x) { return tgamma(x, policies::policy<>()); }So calling a special function with a specific policyis just a matter of defining the policy type to useand passing it as the final parameter. For example,suppose we want `tgamma` to behave in a C-compatiblefashion and set `::errno` when an error occurs, and neverthrow an exception:[import ../../example/policy_eg_1.cpp][policy_eg_1]which outputs:[pre Result of tgamma(30000) is: 1.#INFerrno = 34Result of tgamma(-10) is: 1.#QNANerrno = 33]Alternatively, for ad hoc use, we can use the `make_policy`helper function to create a policy for us: this usage is more
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -