User's Guide

| Home | Libraries | People | FAQ | More

## User's Guide

### Getting Started

#### Installing Ratio

###### Getting Boost.Ratio

Boost.Ratio is in the latest Boost release in the folder `/boost/ratio`. Documentation, tests and examples folder are at `boost/libs/ratio/`.

You can also access the latest (unstable?) state from the Boost trunk directories `boost/ratio` and `libs/ratio`.

Just go to the wiki and follow the instructions there for anonymous SVN access.

###### Where to install Boost.Ratio?

The simple way is to decompress (or checkout from SVN) the files in your BOOST_ROOT directory.

###### Building Boost.Ratio

Boost.Ratio is a header only library, so no need to compile anything, you just need to `include <boost/ratio.hpp>`.

###### Requirements

Boost.Ratio depends on some Boost libraries. For these specific parts you must use either Boost version 1.39.0 or later (even older versions may work).

In particular, Boost.Ratio depends on:

Boost.Config

  for configuration purposes, ...

Boost.Integer

  for cstdint conformance, and integer traits ...

Boost.MPL

  for MPL Assert and bool, logical ...

Boost.StaticAssert

  for STATIC_ASSERT, ...

Boost.TypeTraits

  for is_base, is_convertible ...

Boost.Utility/EnableIf

  for enable_if, ...

###### Building an executable that uses Boost.Ratio

No link is needed.

###### Exception safety

All functions in the library are exception-neutral, providing the strong exception safety guarantee.

###### Thread safety

All functions in the library are thread-unsafe except when noted explicitly.

###### Tested compilers

Boost.Ratio should work with an C++03 conforming compiler. The current version has been tested on:

Windows with

- MSVC 10.0

MinGW with

- GCC 4.5.0
- GCC 4.5.0 -std=c++0x
- GCC 4.5.2
- GCC 4.5.2 -std=c++0x
- GCC 4.6.0
- GCC 4.6.0 -std=c++0x

Ubuntu with * GCC 4.4.6 * GCC 4.4.6 -std=c++0x * GCC 4.5.4 * GCC 4.5.4 -std=c++0x * GCC 4.6.1 * GCC 4.6.1 -std=c++0x * Intel 12.1.3 * Intel 12.1.3 -std=c++0x

OsX with

- GCC 4.1.2
- GCC 4.6.2
- GCC 4.6.2 -std=c++0x
- GCC 4.7.0
- GCC 4.7.0 -std=c++0x
- GCC 4.7.1
- GCC 4.7.1 -std=c++0x
- clang 1.6
- clang 2.9
- clang 2.9 -std=c++0x
- clang 3.0
- clang 3.0 -std=c++0x
- clang 3.1
- clang 3.1 -std=c++0x
- clang 3.1 -std=c++0x -stdlib=libc++
- clang 3.2
- clang 3.2 -std=c++11
- clang 3.2 -std=c++11 -stdlib=libc++

| Note
Please let us know how this works on other platforms/compilers.

| Note
Please send any questions, comments and bug reports to boost <at> lists <dot> boost <dot> org.

### Tutorial

##### Ratio

`ratio` is a general purpose utility inspired by Walter Brown allowing one to easily and safely compute rational values at compile-time. The `ratio` class catches all errors (such as divide by zero and overflow) at compile time. It is used in the duration and `time_point` classes to efficiently create units of time. It can also be used in other "quantity" libraries or anywhere there is a rational constant which is known at compile-time. The use of this utility can greatly reduce the chances of run-time overflow because the `ratio` (and any ratios resulting from `ratio` arithmetic) are always reduced to the lowest terms.

`ratio` is a template taking two `intmax_ts`, with the second defaulted to 1. In addition to copy constructors and assignment, it only has two public members, both of which are `static const intmax_t`. One is the numerator of the `ratio` and the other is the denominator. The `ratio` is always normalized such that it is expressed in lowest terms, and the denominator is always positive. When the numerator is 0, the denominator is always 1.

Example:

    typedef ratio<5, 3>   five_thirds;
    // five_thirds::num == 5, five_thirds::den == 3

    typedef ratio<25, 15> also_five_thirds;
    // also_five_thirds::num == 5, also_five_thirds::den == 3

    typedef ratio_divide<five_thirds, also_five_thirds>::type one;
    // one::num == 1, one::den == 1

This facility also includes convenience typedefs for the SI prefixes `atto` through `exa` corresponding to their internationally recognized definitions (in terms of `ratio`). This is a tremendous syntactic convenience. It will prevent errors in specifying constants as one no longer has to double count the number of zeros when trying to write millions or billions.

Example:

    typedef ratio_multiply<ratio<5>, giga>::type _5giga;
    // _5giga::num == 5000000000, _5giga::den == 1

    typedef ratio_multiply<ratio<5>, nano>::type _5nano;
    // _5nano::num == 1, _5nano::den == 200000000

##### Ratio I/O

For each `ratio<N, D>` there exists a `ratio_string<ratio<N, D>, CharT>` for which you can query two strings: `symbol` and `prefix`. For those `ratio`'s that correspond to an SI prefix prefix corresponds to the internationally recognized prefix, stored as a `basic_string<CharT>`. For example `ratio_string<mega, char>::prefix()` returns `string("mega")`. For those `ratio`s that correspond to an SI prefix `symbol` corresponds to the internationally recognized symbol, stored as a `basic_string<CharT>`. For example, `ratio_string<mega, char>::symbol()` returns `string("M")`. For all other `ratio`s, both `prefix()` and `symbol()` return a `basic_string` containing "[`ratio::num/ratio::den`]".

`ratio_string<ratio<N, D>, CharT>` is only defined for four character types:

- `char`: UTF-8
- `char16_t`: UTF-16
- `char32_t`: UTF-32
- `wchar_t`: UTF-16 (if wchar_t is 16 bits) or UTF-32

When the character is char, UTF-8 will be used to encode the names. When the character is `char16_t`, UTF-16 will be used to encode the names. When the character is `char32_t`, UTF-32 will be used to encode the names. When the character is `wchar_t`, the encoding will be UTF-16 if `wchar_t` is 16 bits, and otherwise UTF-32.

The `symbol` (Greek mu or μ) for micro is defined by Unicode to be U+00B5.

Examples:

    #include <boost/ratio/ratio_io.hpp>
    #include <iostream>

    int main()
    {
        using namespace std;
        using namespace boost;

        cout << "ratio_string<deca, char>::prefix() = "
             <<  ratio_string<deca, char>::prefix() << '\n';
        cout << "ratio_string<deca, char>::symbol() = "
             <<  ratio_string<deca, char>::symbol() << '\n';

        cout << "ratio_string<giga, char>::prefix() = "
             <<  ratio_string<giga, char>::prefix() << '\n';
        cout << "ratio_string<giga, char>::symbol() = "
             <<  ratio_string<giga, char>::symbol() << '\n';

        cout << "ratio_string<ratio<4, 6>, char>::prefix() = "
             <<  ratio_string<ratio<4, 6>, char>::prefix() << '\n';
        cout << "ratio_string<ratio<4, 6>, char>::symbol() = "
             <<  ratio_string<ratio<4, 6>, char>::symbol() << '\n';
    }

The output will be

    ratio_string<deca, char>::prefix() = deca
    ratio_string<deca, char>::symbol() = da
    ratio_string<giga, char>::prefix() = giga
    ratio_string<giga, char>::symbol() = G
    ratio_string<ratio<4, 6>, char>::prefix() = [2/3]
    ratio_string<ratio<4, 6>, char>::symbol() = [2/3]

##### Ratio MPL Numeric Metafunctions

With the view of the _ratio class as a Rational Constant we can mix _ratio<> and Boost.MPL Integral Constants in the same expression, as in

    typedef mpl::times<int_<5>, giga>::type _5giga;
    // _5giga::num == 5000000000, _5giga::den == 1

    typedef mpl::times<int_<5>, nano>::type _5nano;
    // _5nano::num == 1, _5nano::den == 200000000

### Example

#### SI units

This example illustrates the use of type-safe physics code interoperating with `boost::chrono::duration` types, taking advantage of the Boost.Ratio infrastructure and design philosophy.

Let's start by defining a `length` class template that mimics `boost::chrono::duration`, which represents a time duration in various units, but restricts the representation to `double` and uses Boost.Ratio for length unit conversions:

    template <class Ratio>
    class length {
    private:
        double len_;
    public:
        typedef Ratio ratio;
        length() : len_(1) {}
        length(const double& len) : len_(len) {}

        template <class R>
        length(const length<R>& d)
                : len_(d.count() * boost::ratio_divide<Ratio, R>::type::den /
                                   boost::ratio_divide<Ratio, R>::type::num) {}

        double count() const {return len_;}

        length& operator+=(const length& d) {len_ += d.count(); return *this;}
        length& operator-=(const length& d) {len_ -= d.count(); return *this;}

        length operator+() const {return *this;}
        length operator-() const {return length(-len_);}

        length& operator*=(double rhs) {len_ *= rhs; return *this;}
        length& operator/=(double rhs) {len_ /= rhs; return *this;}
    };

Here's a small sampling of length units:

    typedef length<boost::ratio<1> >          meter;        // set meter as "unity"
    typedef length<boost::centi>              centimeter;   // 1/100 meter
    typedef length<boost::kilo>               kilometer;    // 1000  meters
    typedef length<boost::ratio<254, 10000> > inch;         // 254/10000 meters

Note that since `length`'s template parameter is actually a generic ratio type, so we can use boost::ratio allowing for more complex length units:

    typedef length<boost::ratio_multiply<boost::ratio<12>, inch::ratio>::type>   foot;  // 12 inchs
    typedef length<boost::ratio_multiply<boost::ratio<5280>, foot::ratio>::type> mile;  // 5280 feet

Now we need a floating point-based definition of seconds:

    typedef boost::chrono::duration<double> seconds;                         // unity

We can even support sub-nanosecond durations:

    typedef boost::chrono::duration<double,  boost::pico> picosecond;  // 10^-12 seconds
    typedef boost::chrono::duration<double, boost::femto> femtosecond; // 10^-15 seconds
    typedef boost::chrono::duration<double,  boost::atto> attosecond;  // 10^-18 seconds

Finally, we can write a proof-of-concept of an SI units library, hard-wired for meters and floating point seconds, though it will accept other units:

    template <class R1, class R2>
    class quantity
    {
        double q_;
    public:
        typedef R1 time_dim;
        typedef R2 distance_dim;
        quantity() : q_(1) {}

        double get() const {return q_;}
        void set(double q) {q_ = q;}
    };

    template <>
    class quantity<boost::ratio<1>, boost::ratio<0> >
    {
        double q_;
    public:
        quantity() : q_(1) {}
        quantity(seconds d) : q_(d.count()) {}  // note:  only User1::seconds needed here

        double get() const {return q_;}
        void set(double q) {q_ = q;}
    };

    template <>
    class quantity<boost::ratio<0>, boost::ratio<1> >
    {
        double q_;
    public:
        quantity() : q_(1) {}
        quantity(meter d) : q_(d.count()) {}  // note:  only User1::meter needed here

        double get() const {return q_;}
        void set(double q) {q_ = q;}
    };

    template <>
    class quantity<boost::ratio<0>, boost::ratio<0> >
    {
        double q_;
    public:
        quantity() : q_(1) {}
        quantity(double d) : q_(d) {}

        double get() const {return q_;}
        void set(double q) {q_ = q;}
    };

That allows us to create some useful SI-based unit types:

    typedef quantity<boost::ratio<0>, boost::ratio<0> >  Scalar;
    typedef quantity<boost::ratio<1>, boost::ratio<0> >  Time;         // second
    typedef quantity<boost::ratio<0>, boost::ratio<1> >  Distance;     // meter
    typedef quantity<boost::ratio<-1>, boost::ratio<1> > Speed;        // meter/second
    typedef quantity<boost::ratio<-2>, boost::ratio<1> > Acceleration; // meter/second^2

To make quantity useful, we need to be able to do arithmetic:

    template <class R1, class R2, class R3, class R4>
    quantity<typename boost::ratio_subtract<R1, R3>::type,
             typename boost::ratio_subtract<R2, R4>::type>
    operator/(const quantity<R1, R2>& x, const quantity<R3, R4>& y)
    {
        typedef quantity<typename boost::ratio_subtract<R1, R3>::type,
                        typename boost::ratio_subtract<R2, R4>::type> R;
        R r;
        r.set(x.get() / y.get());
        return r;
    }

    template <class R1, class R2, class R3, class R4>
    quantity<typename boost::ratio_add<R1, R3>::type,
             typename boost::ratio_add<R2, R4>::type>
    operator*(const quantity<R1, R2>& x, const quantity<R3, R4>& y)
    {
        typedef quantity<typename boost::ratio_add<R1, R3>::type,
                        typename boost::ratio_add<R2, R4>::type> R;
        R r;
        r.set(x.get() * y.get());
        return r;
    }

    template <class R1, class R2>
    quantity<R1, R2>
    operator+(const quantity<R1, R2>& x, const quantity<R1, R2>& y)
    {
        typedef quantity<R1, R2> R;
        R r;
        r.set(x.get() + y.get());
        return r;
    }

    template <class R1, class R2>
    quantity<R1, R2>
    operator-(const quantity<R1, R2>& x, const quantity<R1, R2>& y)
    {
        typedef quantity<R1, R2> R;
        R r;
        r.set(x.get() - y.get());
        return r;
    }

With all of the foregoing scaffolding, we can now write an exemplar of a type-safe physics function:

    Distance
    compute_distance(Speed v0, Time t, Acceleration a)
    {
        return v0 * t + Scalar(.5) * a * t * t;  // if a units mistake is made here it won't compile
    }

Finally, we can exercise what we've created, even using custom time durations (`User1::seconds`) as well as Boost time durations (`boost::chrono::hours`). The input can be in arbitrary, though type-safe, units, the output is always in SI units. (A complete Units library would support other units, of course.)

    int main()
    {
        typedef boost::ratio<8, BOOST_INTMAX_C(0x7FFFFFFFD)> R1;
        typedef boost::ratio<3, BOOST_INTMAX_C(0x7FFFFFFFD)> R2;
        typedef User1::quantity<boost::ratio_subtract<boost::ratio<0>, boost::ratio<1> >::type,
                                 boost::ratio_subtract<boost::ratio<1>, boost::ratio<0> >::type > RR;
        typedef boost::ratio_subtract<R1, R2>::type RS;
        std::cout << RS::num << '/' << RS::den << '\n';

        std::cout << "*************\n";
        std::cout << "* testUser1 *\n";
        std::cout << "*************\n";
        User1::Distance d( User1::mile(110) );
        User1::Time t( boost::chrono::hours(2) );

        RR r=d / t;
        //r.set(d.get() / t.get());

        User1::Speed rc= r;

        User1::Speed s = d / t;
        std::cout << "Speed = " << s.get() << " meters/sec\n";
        User1::Acceleration a = User1::Distance( User1::foot(32.2) ) / User1::Time() / User1::Time();
        std::cout << "Acceleration = " << a.get() << " meters/sec^2\n";
        User1::Distance df = compute_distance(s, User1::Time( User1::seconds(0.5) ), a);
        std::cout << "Distance = " << df.get() << " meters\n";
        std::cout << "There are "
            << User1::mile::ratio::den << '/' << User1::mile::ratio::num << " miles/meter";
        User1::meter mt = 1;
        User1::mile mi = mt;
        std::cout << " which is approximately " << mi.count() << '\n';
        std::cout << "There are "
            << User1::mile::ratio::num << '/' << User1::mile::ratio::den << " meters/mile";
        mi = 1;
        mt = mi;
        std::cout << " which is approximately " << mt.count() << '\n';
        User1::attosecond as(1);
        User1::seconds sec = as;
        std::cout << "1 attosecond is " << sec.count() << " seconds\n";
        std::cout << "sec = as;  // compiles\n";
        sec = User1::seconds(1);
        as = sec;
        std::cout << "1 second is " << as.count() << " attoseconds\n";
        std::cout << "as = sec;  // compiles\n";
        std::cout << "\n";
        return 0;
    }

See the source file example/si_physics.cpp

### External Resources

C++ Standards Committee's current Working Paper

  The most authoritative reference material for the library is the C++ Standards Committee's current Working Paper (WP). 20.6 Compile-time rational arithmetic "ratio"

N2661 - A Foundation to Sleep On

  From Howard E. Hinnant, Walter E. Brown, Jeff Garland and Marc Paterno. Is very informative and provides motivation for key design decisions

LWG 1281. CopyConstruction and Assignment between ratios having the same normalized form

  From Vicente Juan Botet Escriba.