Иногда то, что вы хотите сделать, это просто изменить набор политик в рамках текущей области:Единственное, что вы не должны делать в этой ситуации, это использовать макросы конфигурации, так как это может привести к нарушениям «Правила одного определения». Вместо этого библиотека предоставляет пару макросов специально для этой цели.
Рассмотрим сначала специальные функции: можно объявить набор экспедиторских функций, которые все используют конкретную политику с помощью макроса. BOOST_MATH_DECLARE_SPECIAL_FUNCTIONSПолитика. Этот макрос должен использоваться либо внутри уникального пространства имен, выделенного для этой цели (например, пространство имен C для политики в стиле C), либо в неназванном пространстве имен, если вы просто хотите, чтобы функции, видимые в глобальном масштабе, были доступны только для текущего файла.
Предположим, что мы хотим<C::foo()
>вести себя совместимым образом и установить<::errno
>на ошибку, а не бросать какие-либо исключения.
Мы начнем с включения необходимого заголовка для нашей функции:
#include <boost/math/special_functions.hpp>
Откройте пространство имен C, которое мы будем использовать для наших функций, и определите тип политики, который мы хотим: в этом случае C-стиль, который устанавливает::errno и возвращает стандартное значение, а не выбрасывает исключения.
Любая политика, которую мы здесь не указываем, унаследует дефолты.
namespace C
{
using boost::math::policies::policy;
using boost::math::policies::domain_error;
using boost::math::policies::pole_error;
using boost::math::policies::overflow_error;
using boost::math::policies::evaluation_error;
using boost::math::policies::errno_on_error;
typedef policy<
domain_error<errno_on_error>,
pole_error<errno_on_error>,
overflow_error<errno_on_error>,
evaluation_error<errno_on_error>
> c_policy;
Все, что нам нужно сделать сейчас, это вызвать BOOST_MATH_DECLARE_SPECIAL_FUNCTIONS Макро, передающий нашу политику типа c_policy как единственный аргумент:
BOOST_MATH_DECLARE_SPECIAL_FUNCTIONS(c_policy)
}
Теперь у нас есть набор функций пересылки, определенных в пространстве имен C, которые выглядят примерно так:
template <class RealType>
inline typename boost::math::tools::promote_args<RT>::type
tgamma(RT z)
{
return boost::math::tgamma(z, c_policy());
}
Когда мы звоним<C::tgamma(z)
>, мы действительно звоним<boost::math::tgamma(z,
C::c_policy())
>:
int main()
{
errno = 0;
cout << "Result of tgamma(30000) is: "
<< C::tgamma(30000) << endl;
cout << "errno = " << errno << endl;
cout << "Result of tgamma(-10) is: "
<< C::tgamma(-10) << endl;
cout << "errno = " << errno << endl;
}
Какие выходы:
Result of C::tgamma(30000) is: 1.#INF
errno = 34
Result of C::tgamma(-10) is: 1.#QNAN
errno = 33
Этот механизм особенно полезен, когда мы хотим определить политику всего проекта и не хотим модифицировать источник Boost или устанавливать макросы построения проекта (возможно, хрупкие и легко забываемые).
Тот же механизм хорошо работает и в области файлов, используя неназванное пространство имен, мы можем гарантировать, что эти декларации не противоречат каким-либо альтернативным политикам, присутствующим в других единицах перевода:
#include <boost/math/special_functions.hpp>
namespace mymath
{
using namespace boost::math::policies;
typedef policy<
domain_error<errno_on_error>,
pole_error<errno_on_error>,
overflow_error<errno_on_error>,
evaluation_error<errno_on_error>
> c_policy;
BOOST_MATH_DECLARE_SPECIAL_FUNCTIONS(c_policy)
Когда мы звоним<mymath::tgamma(z)
>, мы действительно звоним<boost::math::tgamma(z,
anonymous-namespace::c_policy())
>.
}
int main()
{
errno = 0;
cout << "Result of tgamma(30000) is: "
<< mymath::tgamma(30000) << endl;
cout << "errno = " << errno << endl;
cout << "Result of tgamma(-10) is: "
<< mymath::tgamma(-10) << endl;
cout << "errno = " << errno << endl;
}
Политика обработки статистических распределений очень похожа, за исключением того, что в настоящее время макросистемы BOOST_MATH_DECLARE_DISTRIBUTIONS принимает два параметра: тип плавающей точки для использования и тип политики для применения. Например:
BOOST_MATH_DECLARE_DISTRIBUTIONS(double, mypolicy)
Результаты набора типдефов определяются следующим образом:
typedef boost::math::normal_distribution<double, mypolicy> normal;
Имя каждого типа DEF совпадает с именем шаблона класса распределения, но без суффикса «_distribution».
Предположим, что мы хотим, чтобы набор распределений вел себя следующим образом:
- Возврат бесконечности при переливе, а не выбрасывание исключения.
- Не делайте никакого продвижения от двойного к длинному двойному внутри.
- Возврат ближайшего целого результата из квантилей дискретных распределений.
Начнем с включения необходимого заголовка для всех дистрибутивов:
#include <boost/math/distributions.hpp>
Откройте соответствующее пространство имен, назвав его<my_distributions
>для наших дистрибутивов, и определите тип политики, который мы хотим. Любая политика, которую мы не указываем здесь, наследует дефолты:
namespace my_distributions
{
using namespace boost::math::policies;
typedef policy<
overflow_error<errno_on_error>,
promote_double<false>,
discrete_quantile<integer_round_nearest>
> my_policy;
Все, что нам нужно сделать сейчас, это вызвать BOOST_MATH_DECLARE_DISTRIBUTIONS макрос, проходящий тип плавающей точки<double
>и типы политики<my_policy
>в качестве аргументов:
BOOST_MATH_DECLARE_DISTRIBUTIONS(double, my_policy)
}
Теперь у нас есть набор типдефов, определенных в пространстве имен my_distributions, которые выглядят примерно так:
typedef boost::math::normal_distribution<double, my_policy> normal;
typedef boost::math::cauchy_distribution<double, my_policy> cauchy;
typedef boost::math::gamma_distribution<double, my_policy> gamma;
Поэтому, когда мы используем my_distributions::normal, мы действительно используем<boost::math::normal_distribution<double,my_policy>
>:
int main()
{
my_distributions::normal norm(10, 2);
errno = 0;
cout << "Result of quantile(norm, 0) is: "
<< quantile(norm, 0) << endl;
cout << "errno = " << errno << endl;
errno = 0;
cout << "Result of quantile(norm, 1) is: "
<< quantile(norm, 1) << endl;
cout << "errno = " << errno << endl;
my_distributions::binomial binom(20, 0.25);
cout << "Result of quantile(binom, 0.05) is: "
<< quantile(binom, 0.05) << endl;
cout << "Result of quantile(complement(binom, 0.05)) is: "
<< quantile(complement(binom, 0.05)) << endl;
}
Какие выходы:
Result of quantile(norm, 0) is: -1.#INF
errno = 34
Result of quantile(norm, 1) is: 1.#INF
errno = 34
Result of quantile(binom, 0.05) is: 1
Result of quantile(complement(binom, 0.05)) is: 8
Этот механизм особенно полезен, когда мы хотим определить политику всего проекта и не хотим изменять источник Boost или устанавливать макросы сборки проекта (возможно, хрупкие и легко забываемые).
![[Note]](/img/note.png) |
Note |
Существует важное ограничение: вы можете не использовать макросы BOOST_MATH_DECLARE_DISTRIBUTIONS и BOOST_MATH_DECLARE_SPECIAL_FUNCTIONS.в одноимённом пространстве*, так как это создает двусмысленности между функциями и распределениями одного и того же имени. |
Как и прежде, этот же механизм хорошо работает в области файлов: используя неназванное пространство имен, мы можем гарантировать, что эти декларации не противоречат каким-либо альтернативным политикам, присутствующим в других единицах перевода:
#include <boost/math/distributions.hpp>
namespace
{
using namespace boost::math::policies;
typedef policy<
overflow_error<errno_on_error>,
promote_double<false>,
discrete_quantile<integer_round_nearest>
> my_policy;
BOOST_MATH_DECLARE_DISTRIBUTIONS(double, my_policy)
}
int main()
{
normal norm(10, 2);
errno = 0;
cout << "Result of quantile(norm, 0) is: "
<< quantile(norm, 0) << endl;
cout << "errno = " << errno << endl;
errno = 0;
cout << "Result of quantile(norm, 1) is: "
<< quantile(norm, 1) << endl;
cout << "errno = " << errno << endl;
binomial binom(20, 0.25);
cout << "Result of quantile(binom, 0.05) is: "
<< quantile(binom, 0.05) << endl;
cout << "Result of quantile(complement(binom, 0.05)) is: "
<< quantile(complement(binom, 0.05)) << endl;
}