| 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((std::integral_constant<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((std::integral_constant<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. Boost.Multiprecision has a large number of arbitrary precision floating point types to aid with this.

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",
                   std::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 std::integral_constant<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 std::integral_constant<int, construct_from_float>)
                {
                  return 3.141592653589793238462643383279502884e+00F;
                }
                static inline  T get(const std::integral_constant<int, construct_from_double>&)
                {
                  return 3.141592653589793238462643383279502884e+00;
                }
                static inline  T get(const std::integral_constant<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 std::integral_constant<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 std::integral_constant<int, 0>&)
                {
                  return tools::digits<T>() > max_string_digits ? compute<0>() : get(std::integral_constant<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