Real Number Parsers (float_, double_, etc.)

| Home | Libraries | People | FAQ | More

##### Real Number Parsers (`float_`, `double_`, etc.)

###### Description

The `real_parser` can parse real numbers of arbitrary length and size limited by its template parameter, `T`. The numeric base type `T` can be a user defined numeric type such as fixed_point (fixed point reals) and bignum (unlimited precision numbers) as long as the type follows certain expression requirements (documented below).

###### Header

    // forwards to <boost/spirit/home/qi/numeric/real.hpp>
    #include <boost/spirit/include/qi_real.hpp>

Also, see Include Structure.

###### Namespace

Name
`boost::spirit::lit // alias: boost::spirit::qi::lit`
`boost::spirit::float_ // alias: boost::spirit::qi::float_`
`boost::spirit::double_ // alias: boost::spirit::qi::double_`
`boost::spirit::long_double // alias: boost::spirit::qi::long_double`

| Note
`lit` is reused by the Character Parsers, and the Numeric Parsers. In general, a char parser is created when you pass in a character, and a numeric parser is created when you use a numeric literal.

###### Synopsis

    template <typename T, typename RealPolicies>
    struct real_parser;

###### Template parameters

Parameter | Description | Default
--- | --- | ---
`T` | The numeric base type of the numeric parser. | none
`RealPolicies` | Policies control the parser's behavior. | `real_policies<T>`

###### Model of

> `PrimitiveParser`

Notation

`n`

  An object of `T`, the numeric base type.

`num`

  Numeric literal, any real value, or a Lazy Argument that evaluates to a real value.

`RP`

  A `RealPolicies` (type).

`exp`

  A `int` exponent.

`b`

  A `bool` flag.

`f`, `l`

  `ForwardIterator`. first/last iterator pair.

###### Expression Semantics

Semantics of an expression is defined only where it differs from, or is not defined in `PrimitiveParser`.

Expression | Semantics
--- | ---

    float_
    double_
    long_double

Parse a real using the default policies (`real_policies<T>`).

    lit(num)
    float_(num)
    double_(num)
    long_double(num)

Match the literal `num` using the default policies (`real_policies<T>`). The parser will fail if the parsed value is not equal to the specified value.

    real_parser<
        T, RealPolicies
    >()

Parse a real of type `T` using `RealPolicies`.

    real_parser<
        T, RealPolicies
    >()(num)

Match the literal `num` of type `T` using `RealPolicies`. The parser will fail if the parsed value is not equal to the specified value.

###### Attributes

Expression | Attribute
--- | ---

    lit(num)

`unused`

    float_
    float_(num)

`float`

    double_
    double_(num)

`double`

    long_double
    long_double(num)

`long double`

    real_parser<
        T, RealPolicies
    >()
    real_parser<
        T, RealPolicies
    >()(num)

`T`

###### Complexity

> O(N), where N is the number of characters (including the digits, exponent, sign, etc.) being parsed.

###### Minimum Expression Requirements for `T`

The numeric base type, `T`, the minimum expression requirements listed below must be valid. Take note that additional requirements may be imposed by custom policies.

Expression | Semantics
--- | ---
`T()` | Default construct.
`T(0)` | Construct from an `int`.
`n + n` | Addition.
`n - n` | Subtraction.
`n * n` | Multiplication.
`std::numeric_limits<T>::is_bounded` | `true` or `false` if `T` bounded.
`std::numeric_limits<T>::digits` | Maximum Digits for `T`, radix digits. Required only if `T` is bounded.
`std::numeric_limits<T>::digits10` | Maximum Digits for `T`, base 10. Required only if `T` is bounded.
`std::numeric_limits<T>::max()` | Maximum value for `T`. Required only if `T` is bounded.
`std::numeric_limits<T>::min()` | Minimum value for `T`. Required only if `T` is bounded.
`boost::spirit::traits::scale(exp, n)` | Multiply `n` by `10^exp`. Default implementation is provided for `float`, `double` and `long double`.
`boost::spirit::traits::negate(b, n)` | Negate `n` if `b` is `true`. Default implementation is provided for `float`, `double` and `long double`.
`boost::spirit::traits::is_equal_to_one(n)` | Return `true` if `n` is equal to `1.0`. Default implementation is provided for `float`, `double` and `long double`.

| Note
The additional spirit real number traits above are provided to allow custom implementations to implement efficient real number parsers. For example, for certain custom real numbers, scaling to a base 10 exponent is a very cheap operation.

###### `RealPolicies`

The `RealPolicies` template parameter is a class that groups all the policies that control the parser's behavior. Policies control the real number parsers' behavior.

The default is `real_policies<T>`. The default is provided to take care of the most common case (there are many ways to represent, and hence parse, real numbers). In most cases, the default policies are sufficient and can be used straight out of the box. They are designed to parse C/C++ style floating point numbers of the form `nnn.fff.Eeee` where `nnn` is the whole number part, `fff` is the fractional part, `E` is `'e'` or `'E'` and `eee` is the exponent optionally preceded by `'-'` or `'+'` with the additional detection of NaN and Inf as mandated by the C99 Standard and proposed for inclusion into the C++0x Standard: nan, nan(...), inf and infinity (the matching is case-insensitive). This corresponds to the following grammar:

    sign
        =   lit('+') | '-'
        ;

    nan
        =   -lit("1.0#") >> no_case["nan"]
            >> -('(' >> *(char_ - ')') >> ')')
        ;

    inf
        =   no_case[lit("inf") >> -lit("inity")]
        ;

    floating_literal
        =   -sign >>
            (       nan
                |   inf
                |   fractional_constant >> -exponent_part
                |  +digit >> exponent_part
            )
        ;

    fractional_constant
        =  *digit >> '.' >> +digit
        |  +digit >> -lit('.')
        ;

    exponent_part
        =   (lit('e') | 'E') >> -sign >> +digit
        ;

There are four `RealPolicies` predefined for immediate use:

Table 4. Predefined Policies

Policies | Description
--- | ---
`ureal_policies<double>` | Without sign.
`real_policies<double>` | With sign.
`strict_ureal_policies<double>` | Without sign, dot required.
`strict_real_policies<double>` | With sign, dot required.

| Note
Integers are considered a subset of real numbers, so for instance, `double_` recognizes integer numbers (without a dot) just as well. To avoid this ambiguity, `strict_ureal_policies` and `strict_real_policies` require a dot to be present for a number to be considered a successful match.

###### `RealPolicies` Expression Requirements

For models of `RealPolicies` the following expressions must be valid:

Expression | Semantics
--- | ---
`RP::allow_leading_dot` | Allow leading dot.
`RP::allow_trailing_dot` | Allow trailing dot.
`RP::expect_dot` | Require a dot.
`RP::parse_sign(f, l)` | Parse the prefix sign (e.g. '-'). Return `true` if successful, otherwise `false`.
`RP::parse_n(f, l, n)` | Parse the integer at the left of the decimal point. Return `true` if successful, otherwise `false`. If successful, place the result into `n`.
`RP::parse_dot(f, l)` | Parse the decimal point. Return `true` if successful, otherwise `false`.
`RP::parse_frac_n(f, l, n)` | Parse the fraction after the decimal point. Return `true` if successful, otherwise `false`. If successful, place the result into `n`.
`RP::parse_exp(f, l)` | Parse the exponent prefix (e.g. 'e'). Return `true` if successful, otherwise `false`.
`RP::parse_exp_n(f, l, n)` | Parse the actual exponent. Return `true` if successful, otherwise `false`. If successful, place the result into `n`.
`RP::parse_nan(f, l, n)` | Parse a NaN. Return `true` if successful, otherwise `false`. If successful, place the result into `n`.
`RP::parse_inf(f, l, n)` | Parse an Inf. Return `true` if successful, otherwise `false`. If successful, place the result into `n`.

The `parse_nan` and `parse_inf` functions get called whenever:

> a number to parse does not start with a digit (after having successfully parsed an optional sign)

or

> after a real number of the value 1 (having no exponential part and a fractional part value of 0) has been parsed.

The first call recognizes representations of NaN or Inf starting with a non-digit character (such as NaN, Inf, QNaN etc.). The second call recognizes representation formats starting with a `1.0` (such as `"1.0#NAN"` or `"1.0#INF"` etc.).

The functions should return true if a Nan or Inf has been found. In this case the attribute `n` should be set to the matched value (NaN or Inf). The optional sign will be automatically applied afterwards.

###### `RealPolicies` Specializations

The easiest way to implement a proper real parsing policy is to derive a new type from the type `real_policies` while overriding the aspects of the parsing which need to be changed. For example, here's the implementation of the predefined `strict_real_policies`:

    template <typename T>
    struct strict_real_policies : real_policies<T>
    {
        static bool const expect_dot = true;
    };

###### Example

| Note
The test harness for the example(s) below is presented in the Basics Examples section.

Some using declarations:

    using boost::phoenix::val;
    using boost::spirit::qi::double_;
    using boost::spirit::qi::real_parser;
    using boost::spirit::qi::lit;

Basic real number parsing:

    // double
    test_parser("+12345e6", double_);
    test_parser("-12345e6", double_);
    test_parser("+12345e6", double_(12345e6));
    test_parser("-12345e6", double_(-123456e6));
    test_parser("+12345e6", double_(val(12345e6)));
    test_parser("-12345e6", double_(val(-123456e6)));

    // literals
    test_parser("+12345e6", lit(12345e6));
    test_parser("-12345e6", lit(-123456e6));
    test_parser("+12345e6", lit(val(12345e6)));
    test_parser("-12345e6", lit(val(-123456e6)));

A custom real number policy:

    ///////////////////////////////////////////////////////////////////////////////
    //  These policies can be used to parse thousand separated
    //  numbers with at most 2 decimal digits after the decimal
    //  point. e.g. 123,456,789.01
    ///////////////////////////////////////////////////////////////////////////////
    template <typename T>
    struct ts_real_policies : boost::spirit::qi::ureal_policies<T>
    {
        //  2 decimal places Max
        template <typename Iterator, typename Attribute>
        static bool
        parse_frac_n(Iterator& first, Iterator const& last, Attribute& attr)
        {
            return boost::spirit::qi::
                extract_uint<T, 10, 1, 2, true>::call(first, last, attr);
        }

        //  No exponent
        template <typename Iterator>
        static bool
        parse_exp(Iterator&, Iterator const&)
        {
            return false;
        }

        //  No exponent
        template <typename Iterator, typename Attribute>
        static bool
        parse_exp_n(Iterator&, Iterator const&, Attribute&)
        {
            return false;
        }

        //  Thousands separated numbers
        template <typename Iterator, typename Attribute>
        static bool
        parse_n(Iterator& first, Iterator const& last, Attribute& attr)
        {
            using boost::spirit::qi::uint_parser;
            namespace qi = boost::spirit::qi;

            uint_parser<unsigned, 10, 1, 3> uint3;
            uint_parser<unsigned, 10, 3, 3> uint3_3;

            T result = 0;
            if (parse(first, last, uint3, result))
            {
                bool hit = false;
                T n;
                Iterator save = first;

                while (qi::parse(first, last, ',') && qi::parse(first, last, uint3_3, n))
                {
                    result = result * 1000 + n;
                    save = first;
                    hit = true;
                }

                first = save;
                if (hit)
                    attr = result;
                return hit;
            }
            return false;
        }
    };

And its use:

    real_parser<double, ts_real_policies<double> > ts_real;
    test_parser("123,456,789.01", ts_real);
    test_parser("123,456,789.01", ts_real(123456789.01));