Home > Articles > Programming > C/C++

The C++ Standard Library: Utilities

📄 Contents

  1. 5.6. Compile-Time Fractional Arithmetic with Class ratio<>
  2. 5.7. Clocks and Timers
  • Print
  • + Share This
  • 💬 Discuss
This chapter from C++ Standard Library, The: A Tutorial and Reference, 2nd Edition discusses compile-time fractional arithmetic with class ratio<> and clocks and timers.

5.6. Compile-Time Fractional Arithmetic with Class ratio<>

Since C++11, the C++ standard library provides an interface to specify compile-time fractions and to perform compile-time arithmetic with them. To quote [N2661:Chrono] (with minor modifications):26

  • The ratio utility is a general purpose utility inspired by Walter E. 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 libraries [see Section 5.7, page 143] to efficiently create units of time. It can also be used in other “quantity” libraries (both standard-defined and user-defined), or anywhere there is a rational constant which is known at compile time. The use of this utility can greatly reduce the chances of runtime overflow because a ratio and any ratios resulting from ratio arithmetic are always reduced to lowest terms.

The ratio utility is provided in <ratio>, with class ratio<> defined as follows:

namespace std {
    template <intmax_t N, intmax_t D = 1>
    class ratio {
      public:
        typedef ratio<num,den> type;
        static constexpr intmax_t num;
        static constexpr intmax_t den;
    };
}

intmax_t designates a signed integer type capable of representing any value of any signed integer type. It is defined in <cstdint> or <stdint.h> with at least 64 bits. Numerator and denominator are both public and are automatically reduced to the lowest terms. For example:

// util/ratio1.cpp

#include <ratio>
#include <iostream>
using namespace std;

int main()
{
   typedef ratio<5,3> FiveThirds;
   cout << FiveThirds::num << "/" << FiveThirds::den << endl;

   typedef ratio<25,15> AlsoFiveThirds;
   cout << AlsoFiveThirds::num << "/" << AlsoFiveThirds::den << endl;

   ratio<42,42> one;
   cout << one.num << "/" << one.den << endl;

   ratio<0> zero;
   cout << zero.num << "/" << zero.den << endl;

   typedef ratio<7,-3> Neg;
   cout << Neg::num << "/" << Neg::den << endl;
}

The program has the following output:

5/3
5/3
1/1
0/1
-7/3

Table 5.19 lists the compile-time operations defined for ratio types. The four basic arithmetic compile-time operations +, -, *, and / are defined as ratio_add, ratio_subtract, ratio_multiply, and ratio_divide. The resulting type is a ratio<>, so the static member type yields the corresponding type. For example, the following expression yields std::ratio<13,21> (computed as 141fig01.jpg):

std::ratio_add<std::ratio<2,7>,std::ratio<2,6>>::type

Table 5.19. Operations of ratio<> Types

Operation

Meaning

Result

ratio_add

Reduced sum of ratios

ratio<>

ratio_add

Reduced difference of ratio

ratio<>

ratio_multiply

Reduced product of ratios

ratio<>

ratio_divide

Reduced quotient of ratios

ratio<>

ratio_equal

Checks for!==

true_type or false_type

ratio_not_equal

Checks for !=

true_type or false_type

ratio_less

Checks for <

true_type or false_type

ratio_less_equal

Checks for <=

true_type or false_type

ratio_greater

Checks for >

true_type or false_type

ratio_greater_equal

Checks for >=

true_type or false_type

In addition, you can compare two ratio types with ratio_equal, ratio_not_equal, ratio_less, ratio_less_equal, ratio_greater, or ratio_greater_equal. As with type traits, the resulting type is derived from true_type or false_type (see Section 5.4.2, page 125), so its member value yields true or false:

ratio_equal<ratio<5,3>,ratio<25,15>>::value// yields true

As written, class ratio catches all errors, such as divide by zero and overflow, at compile time. For example,

ratio_multiply<ratio<1,numeric_limits<long long>::max()>,
           ratio<1,2>>::type

won’t compile, because 142fig01.jpg times 1by2.jpg results in an overflow, with the resulting value of the denominator exceeding the limit of its type.

Similarly, the following expression won’t compile, because this is a division by zero:

ratio_divide<fiveThirds,zero>::type

Note, however, that the following expression will compile because the invalid value is detected when member type, num, or den are evaluated:

ratio_divide<fiveThirds,zero>

Predefined ratios make it more convenient to specify large or very small numbers (see Table 5.20). They allow you to specify large numbers without the inconvenient and error-prone listing of zeros. For example,

std::nano

is equivalent to

std::ratio<1,1000000000LL>

which makes it more convenient to specify, for example, nanoseconds (see Section 5.7.2, page 145). The units marked as “optional” are defined only if they are representable by intmax_t.

Table 5.20. Predefined ratio Units

Name

Unit

yocto

142fig01a.jpg

zepto

142fig02a.jpg

atto

142fig03a.jpg

femto

142fig04a.jpg

pico

142fig05a.jpg

nano

142fig06a.jpg

micro

142fig07a.jpg

milli

142fig08a.jpg

centi

142fig09a.jpg

deci

142fig10a.jpg

deca

10

hecto

100

kilo

1, 000

mega

1, 000, 000

giga

1, 000, 000, 000

tera

1, 000, 000, 000, 000

peta

1, 000, 000, 000, 000, 000

exa

1, 000, 000, 000, 000, 000, 000

zetta

1, 000, 000, 000, 000, 000, 000, 000 (optional)

yotta

1, 000, 000, 000, 000, 000, 000, 000, 000 (optional)

  • + Share This
  • 🔖 Save To Your Account

Discussions

comments powered by Disqus