Иногда то, что вы хотите сделать, это просто изменить набор политик в рамках текущей области:Единственное, что вы не должны делать в этой ситуации, это использовать макросы конфигурации, так как это может привести к нарушениям «Правила одного определения». Вместо этого библиотека предоставляет пару макросов специально для этой цели.
Рассмотрим сначала специальные функции: можно объявить набор экспедиторских функций, которые все используют конкретную политику с помощью макроса. 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;
}