Boost.Math エラー時の挙動をカスタマイズする

標準とBoostのround - デフォルトの挙動」からの続きです。
Boost.Mathのround()関数は、デフォルトでは値域エラー時にrounding_error例外を投げます。


Boost.Mathでは、例外が投げられることが好ましくない場合は、その挙動をカスタマイズできます。以下は、エラーを無視する場合の指定です。

#include <iostream>
#include <boost/math/special_functions/round.hpp>
#include <limits>

namespace policies = boost::math::policies;

typedef
    policies::policy<
        policies::rounding_error<policies::ignore_error>
    >
round_policy;

int main()
{
    double x = boost::math::round(std::numeric_limits<double>::quiet_NaN(),
                                  round_policy());
    std::cout << x << std::endl;
}
-1.79769e+308

round()関数の第2引数としてエラー時の動作ポリシーを指定することで、round()関数内でエラーが起きた時の挙動をカスタマイズできます。ポリシーの指定には、boost::math::policies名前空間にある、policyメタ関数を使用します。


policyメタ関数には、エラーの種類ごとの挙動を設定します。round()関数では値域エラーしか起こらないので、rounding_errorのみを指定しています。そしてここでは、値域エラー発生時にignore_error、すなわちエラーを無視するよう指定しています。


他のものも見て行きましょう。


エラー時に例外を投げる(throw_on_error)
エラー時に例外を投げるには、boost::math::policies::throw_on_errorを指定します。値域エラーの場合は、boost::math::rounding_errorを指定します。

#include <iostream>
#include <boost/math/special_functions/round.hpp>
#include <limits>

namespace policies = boost::math::policies;

typedef
    policies::policy<
        policies::rounding_error<policies::throw_on_error>
    >
round_policy;

int main()
{
    try {
        double x = boost::math::round(std::numeric_limits<double>::quiet_NaN(),
                                      round_policy());
    }
    catch (boost::math::rounding_error& e) {
        std::cout << e.what() << std::endl;
    }
}
Error in function boost::math::round<d>(d): Value nan can not be represented in the target integer type.


エラー時にエラー番号を設定する(errno_on_error)
エラー時にerrnoにエラー番号を設定するには、boost::math::policies::errno_on_errorを指定します。値域エラーの場合は、ERANGEが設定されます。

#include <iostream>
#include <boost/math/special_functions/round.hpp>
#include <limits>

namespace policies = boost::math::policies;

typedef
    policies::policy<
        policies::rounding_error<policies::errno_on_error>
    >
round_policy;

int main()
{
    double x = boost::math::round(std::numeric_limits<double>::quiet_NaN(),
                                  round_policy());
    if (errno == ERANGE) {
        std::cout << "range error" << std::endl;
    }
}
range error


ユーザー定義のエラー動作をさせる(user_error)
ユーザー定義のエラー動作をさせるには、boost::math::policies::user_errorを指定します。これを指定すると、値域エラーの場合は、先行宣言のみされているboost::math::policies::user_rounding_error()関数が呼ばれるので、その関数を自分で定義します。

#include <iostream>
#include <boost/math/special_functions/round.hpp>
#include <limits>

namespace policies = boost::math::policies;

typedef
    policies::policy<
        policies::rounding_error<policies::user_error>
    >
round_policy;

namespace boost { namespace math { namespace policies {
    template <class T, class TargetType>
    T user_rounding_error(const char* function, const char* message,
                          const T& val, const TargetType& t)
    {
        std::cout << "rounding error" << std::endl;
        return std::numeric_limits<T>::quiet_NaN();
    }
}}}

int main()
{
    double x = boost::math::round(std::numeric_limits<double>::quiet_NaN(),
                                  round_policy());
}
rounding error


round()関数のエラー時挙動カスタマイズについては以上になります。
エラー時ポリシーの設定は、Boost.Mathでの他の関数にも適用できます。詳細は、以下のドキュメントを参照してください:


Error Handling - Boost Math Library