| Home | Libraries | People | FAQ | More

### Use With User-Defined Types

The most common example of a high-precision user-defined type will probably be Boost.Multiprecision.

The syntax for using the function-call constants with user-defined types is the same as it is in the template class, which is to say we use:

    #include <boost/math/constants/constants.hpp>

    boost::math::constants::pi<UserDefinedType>();

For example:

    boost::math::constants::pi<boost::multiprecision::cpp_dec_float_50>();

giving π with a precision of 50 decimal digits.

However, since the precision of the user-defined type may be much greater than that of the built-in floating point types, how the value returned is created is as follows:

- If the precision of the type is known at compile time:
  - If the precision is less than or equal to that of a `float` and the type is constructible from a `float` then our code returns a `float` literal. If the user-defined type is a literal type then the function call that returns the constant will be a `constexp`.
  - If the precision is less than or equal to that of a `double` and the type is constructible from a `double` then our code returns a `double` literal. If the user-defined type is a literal type then the function call that returns the constant will be a `constexp`.
  - If the precision is less than or equal to that of a `long double` and the type is constructible from a `long double` then our code returns a `long double` literal. If the user-defined type is a literal type then the function call that returns the constant will be a `constexp`.
  - If the precision is less than or equal to that of a `__float128` (and the compiler supports such a type) and the type is constructible from a `__float128` then our code returns a `__float128` literal. If the user-defined type is a literal type then the function call that returns the constant will be a `constexp`.
  - If the precision is less than 100 decimal digits, then the constant will be constructed (just the once, then cached in a thread-safe manner) from a string representation of the constant. In this case the value is returned as a const reference to the cached value.
  - Otherwise the value is computed (just once, then cached in a thread-safe manner). In this case the value is returned as a const reference to the cached value.
- If the precision is unknown at compile time then:
  - If the runtime precision (obtained from a call to `boost::math::tools::digits<T>()`) is less than 100 decimal digits, then the constant is constructed "on the fly" from the string representation of the constant.
  - Otherwise the value is constructed "on the fly" by calculating then value of the constant using the current default precision of the type. Note that this can make use of the constants rather expensive.

In addition, it is possible to pass a `Policy` type as a second template argument, and use this to control the precision:

    #include <boost/math/constants/constants.hpp>

    typedef boost::math::policies::policy<boost::math::policies::digits2<80> > my_policy_type;
    boost::math::constants::pi<MyType, my_policy_type>();

| Note
Boost.Math doesn't know how to control the internal precision of `MyType`, the policy just controls how the selection process above is carried out, and the calculation precision if the result is computed.

It is also possible to control which method is used to construct the constant by specialising the traits class `construction_traits`:

    namespace boost{ namespace math{ namespace constant{

    template <class T, class Policy>
    struct construction_traits
    {
       typedef std::integral_constant<int, N> type;
    };

    }}} // namespaces

Where N takes one of the following values:

N | Meaning
--- | ---
0 | The precision is unavailable at compile time; either construct from a decimal digit string or calculate on the fly depending upon the runtime precision.
1 | Return a float precision constant.
2 | Return a double precision constant.
3 | Return a long double precision constant.
4 | Construct the result from the string representation, and cache the result.
Any other value N | Sets the compile time precision to N bits.

###### Custom Specializing a constant

In addition, for user-defined types that need special handling, it's possible to partially-specialize the internal structure used by each constant. For example, suppose we're using the C++ wrapper around MPFR `mpfr_class`: this has its own representation of Pi which we may well wish to use in place of the above mechanism. We can achieve this by specialising the class template `boost::math::constants::detail::constant_pi`:

    namespace boost{ namespace math{ namespace constants{ namespace detail{

    template<>
    struct constant_pi<mpfr_class>
    {
       template<int N>
       static mpfr_class get(const std::integral_constant<int, N>&)
       {
          // The template param N is one of the values in the table above,
          // we can either handle all cases in one as is the case here,
          // or overload "get" for the different options.
          mpfr_class result;
          mpfr_const_pi(result.get_mpfr_t(), GMP_RNDN);
          return result;
       }
    };

    }}}} // namespaces

###### Diagnosing what meta-programmed code is doing

Finally, since it can be tricky to diagnose what meta-programmed code is doing, there is a diagnostic routine that prints information about how this library will handle a specific type, it can be used like this:

    #include <boost/math/constants/info.hpp>

    int main()
    {
       boost::math::constants::print_info_on_type<MyType>();
    }

If you wish, you can also pass an optional std::ostream argument to the `print_info_on_type` function. Typical output for a user-defined type looks like this:

    Information on the Implementation and Handling of
    Mathematical Constants for Type class boost::math::concepts::real_concept

    Checking for std::numeric_limits<class boost::math::concepts::real_concept> specialisation: no
    boost::math::policies::precision<class boost::math::concepts::real_concept, Policy>
    reports that there is no compile type precision available.
    boost::math::tools::digits<class boost::math::concepts::real_concept>()
    reports that the current runtime precision is
    53 binary digits.
    No compile time precision is available, the construction method
    will be decided at runtime and results will not be cached
    - this may lead to poor runtime performance.
    Current runtime precision indicates that
    the constant will be constructed from a string on each call.