| Home | Libraries | People | FAQ | More

## Defining New Constants

The library provides some helper code to assist in defining new constants; the process for defining a constant called `my_constant` goes like this:

1. Define a function that calculates the value of the constant. This should be a template function, and be placed in `boost/math/constants/calculate_constants.hpp` if the constant is to be added to this library, or else defined at the top of your source file if not.

The function should look like this:

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

    template <class Real>
    template <int N>
    Real constant_my_constant<Real>::compute(BOOST_MATH_EXPLICIT_TEMPLATE_TYPE_SPEC(mpl::int_<N>))
    {
      int required_precision = N ? N : tools::digits<Real>();
      Real result = /* value computed to required_precision bits */ ;
      return result;
    }

    }}}} // namespaces

Then define a placeholder for the constant itself:

    namespace boost{ namespace math{ namespace constants{

    BOOST_DEFINE_MATH_CONSTANT(my_constant, 0.0, "0");

    }}}

For example, to calculate π/2, add to `boost/math/constants/calculate_constants.hpp`

    template <class T>
    template<int N>
    inline T constant_half_pi<T>::compute(BOOST_MATH_EXPLICIT_TEMPLATE_TYPE_SPEC(mpl::int_<N>))
    {
       BOOST_MATH_STD_USING
       return pi<T, policies::policy<policies::digits2<N> > >() / static_cast<T>(2);
    }

Then to `boost/math/constants/constants.hpp` add:

    BOOST_DEFINE_MATH_CONSTANT(half_pi, 0.0, "0");  // Actual values are temporary, we'll replace them later.

| Note
Previously defined constants like pi and e can be used, but by not simply calling `pi<T>()`; specifying the precision via the policy `pi<T, policies::policy<policies::digits2<N> > >()` is essential to ensure full accuracy.

| Warning
Newly defined constants can only be used once they are included in `boost/math/constants/constants.hpp`. So if you add `template <class T, class N> T constant_my_constant{...}`, then you cannot define `constant_my_constant` until you add the temporary `BOOST_DEFINE_MATH_CONSTANT(my_constant, 0.0, "0")`. Failing to do this will result in surprising compile errors:
    error C2143: syntax error : missing ';' before '<'
    error C2433: 'constant_root_two_div_pi' : 'inline' not permitted on data declarations
    error C2888: 'T constant_root_two_div_pi' : symbol cannot be defined within namespace 'detail'
    error C2988: unrecognizable template declaration/definition

2. You will need an arbitrary precision type to use to calculate the value. This library currently supports either `cpp_float`, `NTL::RR` or `mpfr_class` used via the bindings in `boost/math/bindings`. The default is to use `NTL::RR` unless you define an alternate macro, for example, `USE_MPFR` or `USE_CPP_FLOAT` at the start of your program.

3. It is necessary to link to the Boost.Regex library, and probably to your chosen arbitrary precision type library.

4. You need to add `libs\math\include_private` to your compiler's include path as the needed header is not installed in the usual places by default (this avoids a cyclic dependency between the Math and Multiprecision library's headers).

5. The complete program to generate the constant `half_pi` using function `calculate_half_pi` is then:

    #define USE_CPP_FLOAT // If required.
    #include <boost/math/constants/generate.hpp>

    int main()
    {
       BOOST_CONSTANTS_GENERATE(half_pi);
    }

The output from the program is a snippet of C++ code (actually a macro call) that can be cut and pasted into `boost/math/constants/constants.hpp` or else into your own code, for example:

      BOOST_DEFINE_MATH_CONSTANT(half_pi, 1.570796326794896619231321691639751442e+00, "1.57079632679489661923132169163975144209858469968755291048747229615390820314310449931401741267105853399107404326e+00");

This macro BOOST_DEFINE_MATH_CONSTANT inserts a C++ struct code snippet that declares the `float`, `double` and `long double` versions of the constant, plus a decimal digit string representation correct to 100 decimal digits, and all the meta-programming machinery needed to select between them.

The result of an expanded macro for Pi is shown below.

    // Preprocessed pi constant, annotated.

    namespace boost
    {
      namespace math
      {
        namespace constants
        {
          namespace detail
          {
            template <class T> struct constant_pi
            {
              private:
                // Default implementations from string of decimal digits:
                static inline T get_from_string()
                {
                static const T result
                   = detail::convert_from_string<T>("3.14159265358979323846264338327950288419716939937510582097494459230781640628620899862803482534211706798214808651e+00",
                   boost::is_convertible<const char*, T>());
                  return result;
                }
                template <int N> static T compute();

              public:
                // Default implementations from string of decimal digits:
                static inline T get(const mpl::int_<construct_from_string>&)
                {
                  constant_initializer<T, & constant_pi<T>::get_from_string >::do_nothing();
                  return get_from_string();
                }
                // Float, double and long double versions:
                static inline T get(const mpl::int_<construct_from_float>)
                {
                  return 3.141592653589793238462643383279502884e+00F;
                }
                static inline  T get(const mpl::int_<construct_from_double>&)
                {
                  return 3.141592653589793238462643383279502884e+00;
                }
                static inline  T get(const mpl::int_<construct_from_long_double>&)
                {
                  return 3.141592653589793238462643383279502884e+00L;
                }
                // For very high precision that is nonetheless can be calculated at compile time:
                template <int N> static inline T get(const mpl::int_<N>& n)
                {
                  constant_initializer2<T, N, & constant_pi<T>::template compute<N> >::do_nothing();
                  return compute<N>();
                }
                //For true arbitrary precision, which may well vary at runtime.
                static inline T get(const mpl::int_<0>&)
                {
                  return tools::digits<T>() > max_string_digits ? compute<0>() : get(mpl::int_<construct_from_string>());
                }
             }; // template <class T> struct constant_pi
          } //  namespace detail

          // The actual forwarding function (including policy to control precision).
          template <class T, class Policy> inline T pi( )
          {
            return detail:: constant_pi<T>::get(typename construction_traits<T, Policy>::type());
          }
          // The actual forwarding function (using default policy to control precision).
          template <class T> inline  T pi()
          {
            return pi<T, boost::math::policies::policy<> >()
          }
        } //     namespace constants

        // Namespace specific versions, for the three built-in floats:
        namespace float_constants
        {
          static const float pi = 3.141592653589793238462643383279502884e+00F;
        }
        namespace double_constants
        {
          static const double pi = 3.141592653589793238462643383279502884e+00;
        }
        namespace long_double_constants
        {
          static const long double pi = 3.141592653589793238462643383279502884e+00L;
        }
        namespace constants{;
        } // namespace constants
      } // namespace math
    } // namespace boost