Карта сайта Kansoftware
НОВОСТИУСЛУГИРЕШЕНИЯКОНТАКТЫ
Разработка программного обеспечения

Calling User Defined Error Handlers

Boost , Math Toolkit 2.5.0 , Policy Tutorial

Boost C++ Libraries

...one of the most highly regarded and expertly designed C++ library projects in the world. Herb Sutter and Andrei Alexandrescu, C++ Coding Standards

PrevUpHomeNext

Предположим, что мы хотим использовать наши собственные пользовательские обработчики ошибок, а не какие-либо из стандартных, предоставляемых библиотекой. Если мы установим политику для определенного типа ошибки<user_error>, библиотека вызовет обработчика ошибок, предоставленного пользователем. Они объявлены вперед, но не определены в boost/math/policies/error_handling.hpp следующим образом:

namespace boost{ namespace math{ namespace policies{
template <class T>
T user_domain_error(const char* function, const char* message, const T& val);
template <class T>
T user_pole_error(const char* function, const char* message, const T& val);
template <class T>
T user_overflow_error(const char* function, const char* message, const T& val);
template <class T>
T user_underflow_error(const char* function, const char* message, const T& val);
template <class T>
T user_denorm_error(const char* function, const char* message, const T& val);
template <class T>
T user_evaluation_error(const char* function, const char* message, const T& val);
template <class T, class TargetType>
T user_rounding_error(const char* function, const char* message, const T& val, const TargetType& t);
template <class T>
T user_indeterminate_result_error(const char* function, const char* message, const T& val);
}}} // namespaces

Итак, первая задача состоит в том, чтобы включить заголовок, который мы хотим использовать, а затем предоставить определения для наших пользовательских обработчиков ошибок, которые мы хотим использовать. Мы предоставляем только наши специальные обработчики ошибок домена и полюса; другие ошибки, такие как переполнение и недоток, используют по умолчанию.

#include <boost/math/special_functions.hpp>
namespace boost{ namespace math
{
  namespace policies
  {
    template <class T>
    T user_domain_error(const char* function, const char* message, const T& val)
    { // Ignoring function, message and val for this example, perhaps unhelpfully.
       cerr << "Domain Error!" << endl;
       return std::numeric_limits<T>::quiet_NaN();
    }
    template <class T>
    T user_pole_error(const char* function, const char* message, const T& val)
    { // Ignoring function, message and val for this example, perhaps unhelpfully.
       cerr << "Pole Error!" << endl;
       return std::numeric_limits<T>::quiet_NaN();
    }
  } // namespace policies
}} // namespace boost{ namespace math

Теперь нам нужно определить подходящую политику, которая вызовет этих обработчиков, и определить некоторые функции пересылки, которые используют политику:

namespace mymath{
using namespace boost::math::policies;
typedef policy<
   domain_error<user_error>,
   pole_error<user_error>
> user_error_policy;
BOOST_MATH_DECLARE_SPECIAL_FUNCTIONS(user_error_policy)
} // close unnamed namespace

Теперь у нас есть набор функций пересылки, определенных в мимате пространства имен, которые выглядят примерно так:

template <class RealType>
inline typename boost::math::tools::promote_args<RT>::type
   tgamma(RT z)
{
   return boost::math::tgamma(z, user_error_policy());
}

Поэтому, когда мы звоним<mymath::tgamma(z)>, мы действительно звоним<boost::math::tgamma(z, user_error_policy())>, и любые ошибки будут направлены на наших собственных обработчиков ошибок.

int main()
{
   cout << "Result of erf_inv(-10) is: "
      << mymath::erf_inv(-10) << endl;
   cout << "Result of tgamma(-10) is: "
      << mymath::tgamma(-10) << endl;
}

Какие выходы:

  Domain Error!
  Pole Error!
  Result of erf_inv(-10) is: 1.#QNAN
  Result of tgamma(-10) is: 1.#QNAN

Предыдущий пример был хорош и хорош, но пользовательские обработчики ошибок на самом деле не приносили пользы. В этом примере мы реализуем все пользовательские обработчики и покажем, как предоставленная им информация может быть использована для создания хороших отформатированных сообщений об ошибках.

Каждый обработчик ошибок имеет общую форму:

template <class T>
T user_error_type(
   const char* function,
   const char* message,
   const T& val);

и принимает три аргумента:

const char* function

Эта строка содержит один или более спецификаторов формата %1%, которые должны быть заменены именем реального типа T, например, float или double.

const char* message

Сообщение, связанное с ошибкой, обычно содержит спецификатор формата %1%, который следует заменить значением: Однако обратите внимание, что сообщения о переполнении и недопотоке не содержат этого спецификатора %1% (поскольку значениезначениев этих случаях несущественно.

const T& value

Значение, которое вызвало ошибку: либо аргумент функции, если это ошибка домена или полюса, предварительный результат, если это ошибка денормы или оценки, или ноль или бесконечность для ошибок перетока или перетока.

Как и прежде, мы включим заголовки, которые нам нужны:

#include <boost/math/special_functions.hpp>

Далее мы реализуем наши собственные обработчики ошибок для каждого типа ошибок, начиная с ошибок домена:

namespace boost{ namespace math{
namespace policies
{
template <class T>
T user_domain_error(const char* function, const char* message, const T& val)
{

Начнем с защитного программирования, если функция или сообщение пусты.

if(function == 0)
    function = "Unknown function with arguments of type %1%";
if(message == 0)
    message = "Cause unknown with bad argument %1%";

Далее мы отформатируем название функции с именем типа T, возможно, двойным:

std::string msg("Error in function ");
msg += (boost::format(function) % typeid(T).name()).str();

Затем также отформатируйте сообщение об ошибке со значением параметраval, убедившись, что мы выведем все потенциально значимые цифрыval:

msg += ": \n";
int prec = 2 + (std::numeric_limits<T>::digits * 30103UL) / 100000UL;
// int prec = std::numeric_limits<T>::max_digits10; //  For C++0X Standard Library
msg += (boost::format(message) % boost::io::group(std::setprecision(prec), val)).str();

Теперь нам просто нужно что-то сделать с сообщением, мы можем сделать исключение, но для целей этого примера мы просто сбросим сообщение на std::cerr:

std::cerr << msg << std::endl;

Наконец, единственное разумное значение, которое мы можем получить от ошибки домена, это NaN:

   return std::numeric_limits<T>::quiet_NaN();
}

Ошибки поляков по существу являются частным случаем ошибок домена, поэтому в этом примере мы просто вернем результат ошибки домена:

template <class T>
T user_pole_error(const char* function, const char* message, const T& val)
{
   return user_domain_error(function, message, val);
}

Ошибки переполнения очень похожи на ошибки домена, за исключением того, что в параметресообщениянет спецификатора формата %1%:

template <class T>
T user_overflow_error(const char* function, const char* message, const T& val)
{
   if(function == 0)
       function = "Unknown function with arguments of type %1%";
   if(message == 0)
       message = "Result of function is too large to represent";
   std::string msg("Error in function ");
   msg += (boost::format(function) % typeid(T).name()).str();
   msg += ": \n";
   msg += message;
   std::cerr << msg << std::endl;
   // Value passed to the function is an infinity, just return it:
   return val;
}

Ошибки оттока во многом такие же, как и оттоки:

template <class T>
T user_underflow_error(const char* function, const char* message, const T& val)
{
   if(function == 0)
       function = "Unknown function with arguments of type %1%";
   if(message == 0)
       message = "Result of function is too small to represent";
   std::string msg("Error in function ");
   msg += (boost::format(function) % typeid(T).name()).str();
   msg += ": \n";
   msg += message;
   std::cerr << msg << std::endl;
   // Value passed to the function is zero, just return it:
   return val;
}

Денормализованные результаты во многом похожи на отток:

template <class T>
T user_denorm_error(const char* function, const char* message, const T& val)
{
   if(function == 0)
       function = "Unknown function with arguments of type %1%";
   if(message == 0)
       message = "Result of function is denormalised";
   std::string msg("Error in function ");
   msg += (boost::format(function) % typeid(T).name()).str();
   msg += ": \n";
   msg += message;
   std::cerr << msg << std::endl;
   // Value passed to the function is denormalised, just return it:
   return val;
}

Что оставляет нас с ошибками оценки: они возникают, когда возникает внутренняя ошибка, которая предотвращает полную оценку функции. Параметрвалсодержит наиболее близкое приближение к найденному на данный момент результату:

template <class T>
T user_evaluation_error(const char* function, const char* message, const T& val)
{
   if(function == 0)
       function = "Unknown function with arguments of type %1%";
   if(message == 0)
       message = "An internal evaluation error occurred with "
                  "the best value calculated so far of %1%";
   std::string msg("Error in function ");
   msg += (boost::format(function) % typeid(T).name()).str();
   msg += ": \n";
   int prec = 2 + (std::numeric_limits<T>::digits * 30103UL) / 100000UL;
   // int prec = std::numeric_limits<T>::max_digits10; // For C++0X Standard Library
   msg += (boost::format(message) % boost::io::group(std::setprecision(prec), val)).str();
   std::cerr << msg << std::endl;
   // What do we return here?  This is generally a fatal error, that should never occur,
   // so we just return a NaN for the purposes of the example:
   return std::numeric_limits<T>::quiet_NaN();
}
} // policies
}} // boost::math

Теперь нам нужно определить подходящую политику, которая вызовет этих обработчиков, и определить некоторые функции пересылки, которые используют политику:

namespace mymath
{ // unnamed.
using namespace boost::math::policies;
typedef policy<
   domain_error<user_error>,
   pole_error<user_error>,
   overflow_error<user_error>,
   underflow_error<user_error>,
   denorm_error<user_error>,
   evaluation_error<user_error>
> user_error_policy;
BOOST_MATH_DECLARE_SPECIAL_FUNCTIONS(user_error_policy)
} // unnamed namespace

Теперь у нас есть набор функций пересылки, определенных в мимате пространства имен, которые выглядят примерно так:

template <class RealType>
inline typename boost::math::tools::promote_args<RT>::type
   tgamma(RT z)
{
   return boost::math::tgamma(z, user_error_policy());
}

Поэтому, когда мы звоним<mymath::tgamma(z)>, мы действительно в конечном итоге звоним<boost::math::tgamma(z, user_error_policy())>, и любые ошибки будут направлены на наших собственных обработчиков ошибок:

int main()
{
   // Raise a domain error:
   cout << "Result of erf_inv(-10) is: "
      << mymath::erf_inv(-10) << std::endl << endl;
   // Raise a pole error:
   cout << "Result of tgamma(-10) is: "
      << mymath::tgamma(-10) << std::endl << endl;
   // Raise an overflow error:
   cout << "Result of tgamma(3000) is: "
      << mymath::tgamma(3000) << std::endl << endl;
   // Raise an underflow error:
   cout << "Result of tgamma(-190.5) is: "
      << mymath::tgamma(-190.5) << std::endl << endl;
   // Unfortunately we can't predicably raise a denormalised
   // result, nor can we raise an evaluation error in this example
   // since these should never really occur!
} // int main()

Какие выходы:

Error in function boost::math::erf_inv<double>(double, double):
Argument outside range [-1, 1] in inverse erf function (got p=-10).
Result of erf_inv(-10) is: 1.#QNAN
Error in function boost::math::tgamma<long double>(long double):
Evaluation of tgamma at a negative integer -10.
Result of tgamma(-10) is: 1.#QNAN
Error in function boost::math::tgamma<long double>(long double):
Result of tgamma is too large to represent.
Error in function boost::math::tgamma<double>(double):
Result of function is too large to represent
Result of tgamma(3000) is: 1.#INF
Error in function boost::math::tgamma<long double>(long double):
Result of tgamma is too large to represent.
Error in function boost::math::tgamma<long double>(long double):
Result of tgamma is too small to represent.
Result of tgamma(-190.5) is: 0

Обратите внимание, что некоторые вызовы приводят к тому, что обработчик ошибок вызывается более одного раза или для вызова более одного обработчика: это артефакт того факта, что многие функции реализованы с точки зрения одной или нескольких подпрограмм, каждая из которых может иметь свою собственную обработку ошибок. Например,<tgamma(-190.5)>реализуется в терминах<tgamma(190.5)>— который переполняет — формула отражения для<tgamma>затем замечает, что она делится на бесконечность и поэтому оттоки.


PrevUpHomeNext

Статья Calling User Defined Error Handlers раздела Math Toolkit 2.5.0 Policy Tutorial может быть полезна для разработчиков на c++ и boost.




Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.



:: Главная :: Policy Tutorial ::


реклама


©KANSoftWare (разработка программного обеспечения, создание программ, создание интерактивных сайтов), 2007
Top.Mail.Ru

Время компиляции файла: 2024-08-30 11:47:00
2025-05-20 09:23:00/0.008554220199585/0