<html>
<head>
<title>N3363 - A Rational Number Library for C++</title>
</head>
<body>
<table border=0>
<tr>
  <td><b>Doc No:</b></td>
  <td>N3363 = 12-0053</td>
</tr>
<tr>
  <td><b>Date:</b></td>
  <td>2012-02-23</td>
</tr>
<tr>
  <td><b>Reply to:</b>&nbsp;</td>
  <td>Bill Seymour, stdbill<tt>.</tt>h<sup>@</sup>pobox<tt>.</tt>com</td>
</tr>
</table>

<center>
<h2>A Rational Number Library for C++</h2>
<h3>Bill Seymour<br>2012-02-23</h3>
</center>
<hr size=8><a name="overview"><h2>Introduction:</h2></a>

This paper proposes a rational number library for a C++ Technical Specification (TS)
(n&eacute;e Type II Technical Report (TR)).

<p>This is not the first such suggestion.  Back in the 2004-11 post-Redmond mailing,
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1718.pdf">N1718</a>
proposed both a rational number class and an infinite-precision integer class
that would be used for the numerator and denominator.  That paper also did some
analysis of performance issues and proposed allowing normalization to be turned off
temporarily when users could determine that intermediate calculations wouldn&rsquo;t
overflow.  The paper was
<a href="http://wiki.edg.com/twiki/bin/view/Wg21berlin/LibraryWorkingGroup#Tuesday_1_30_5_30">discussed
in LWG in Berlin</a> where there was weak support,
but it seems like it dropped off the radar after that.

<p>Another interesting design is
<a href="http://www.boost.org/doc/libs/1_48_0/libs/rational/"><tt>boost::rational&lt;&gt;</tt></a>
in which the rational number is a class template that allows the numerator and denominator
to be either a bignum or an integer of some fundamental type.  I couldn&rsquo;t find a paper that
formally proposed <tt>boost::rational&lt;&gt;</tt> for the standard library;
but maybe I didn&rsquo;t look hard enough.

<p>There has been some discussion on the library reflector; and it seems to be
controversial whether the rational number class should be a template to allow
instantiating with different integer types (including some kind of bignum).  This paper
proposes a non-template class that just uses <tt>std::intmax_t</tt> internally.
That&rsquo;s all I thought I could get done in time for the post-Kona mailing;
and I wanted to make the basic interface available sooner rather than later
so that interested parties could be thinking about whether I&rsquo;m including
too much or too little.

<p>I expect also to have a revision of this paper in the pre-Portland mailing in which
<tt>rational</tt> is a class template.  The idea is to have two similar designs
to choose from in Portland.

<p>One goal I have is to make the class usable by novices; and I think that
means that I provide I/O and a handful of <tt>&lt;cmath&gt;</tt>-like
functions that make sense for rationals.  Also, all operations should eagerly
normalize the fraction.  (This paper doesn&rsquo;t propose a mechanism for
temporarily turning off normalization as suggested in N1718; but I&rsquo;m
not opposed to that.)

<p>One issue is what to do in the case of overflow:&nbsp;&nbsp;does an operation throw an exception
or just yield undefined behavior?  If we also have a bignum in the same TS,
this question will be moot.

<p>The proposed standardese in this paper is a first draft
modelled on the wording for <tt>complex</tt>.  I expect to
improve the words in the pre-Portland revision.

<p><table border=0><tr><td bgcolor=lightgrey>
Text with a gray background is additional rationale in this document
and is not intended as wording for the TS.
</td></tr></table>

<p><hr size=8><a name="synop"><h2>[rational.math] Rational math</h2></a>

The header <tt>&lt;rational&gt;</tt> defines the <tt>rational</tt> class
and several free functions and operators for doing arithmetic with rational numbers.

<h3>Header <tt>&lt;rational&gt;</tt> synopsis</h3>

<pre>
#include &lt;cstdint&gt; // for intmax_t

namespace std {
namespace experimental { // subnamespace suggested in LWG in Kona
namespace rational {

class rational;

rational operator+(const rational&amp; val);
rational operator-(const rational&amp; val);

rational operator+(const rational&amp; lhs, const rational&amp; rhs);
rational operator-(const rational&amp; lhs, const rational&amp; rhs);
rational operator*(const rational&amp; lhs, const rational&amp; rhs);
rational operator/(const rational&amp; lhs, const rational&amp; rhs);

rational operator+(const rational&amp; lhs, rational::int_type rhs);
rational operator-(const rational&amp; lhs, rational::int_type rhs);
rational operator*(const rational&amp; lhs, rational::int_type rhs);
rational operator/(const rational&amp; lhs, rational::int_type rhs);

rational operator+(rational::int_type lhs, const rational&amp; rhs);
rational operator-(rational::int_type lhs, const rational&amp; rhs);
rational operator*(rational::int_type lhs, const rational&amp; rhs);
rational operator/(rational::int_type lhs, const rational&amp; rhs);

bool operator==(const rational&amp; lhs, const rational&amp; rhs);
bool operator!=(const rational&amp; lhs, const rational&amp; rhs);
bool operator&lt; (const rational&amp; lhs, const rational&amp; rhs);
bool operator&gt; (const rational&amp; lhs, const rational&amp; rhs);
bool operator&lt;=(const rational&amp; lhs, const rational&amp; rhs);
bool operator&gt;=(const rational&amp; lhs, const rational&amp; rhs);

bool operator==(const rational&amp; lhs, rational::int_type rhs);
bool operator!=(const rational&amp; lhs, rational::int_type rhs);
bool operator&lt; (const rational&amp; lhs, rational::int_type rhs);
bool operator&gt; (const rational&amp; lhs, rational::int_type rhs);
bool operator&lt;=(const rational&amp; lhs, rational::int_type rhs);
bool operator&gt;=(const rational&amp; lhs, rational::int_type rhs);

bool operator==(rational::int_type lhs, const rational&amp; rhs);
bool operator!=(rational::int_type lhs, const rational&amp; rhs);
bool operator&lt; (rational::int_type lhs, const rational&amp; rhs);
bool operator&gt; (rational::int_type lhs, const rational&amp; rhs);
bool operator&lt;=(rational::int_type lhs, const rational&amp; rhs);
bool operator&gt;=(rational::int_type lhs, const rational&amp; rhs);

void swap(rational&amp; lhs, rational&amp; rhs); 

rational::int_type floor(const rational&amp; val);
rational::int_type ceil (const rational&amp; val);
rational::int_type trunc(const rational&amp; val);

enum rounding_mode
{
    nearest_even, nearest_odd,
    toward_pos_inf, toward_neg_inf,
    toward_zero, away_from_zero
};
rational::int_type nearest(const rational&amp; val, rounding_mode mode = nearest_even);

rational abs(const rational&amp; val);

rational reciprocal(const rational&amp; val);

rational ipow(const rational&amp; val, int exp);

rational fmod(const rational&amp; dividend, const rational&amp; divisor);
rational remainder(const rational&amp; dividend, const rational&amp; divisor,
                   rounding_mode mode = nearest_even);

template&lt;class intT&gt;
  rational modf(const rational&amp; val, intT* intptr);

rational modf(const rational&amp; val);

template&lt;class intT&gt;
  rational remquo(const rational&amp; dividend, const rational&amp; divisor, intT* intptr,
                  rounding_mode mode = nearest_even);

template&lt;class charT, class traits&gt;
  std::basic_ostream&lt;charT,traits&gt;&amp;
    showden1(std::basic_ostream&lt;charT,traits&gt;&amp; str);

template&lt;class charT, class traits&gt;
  std::basic_ostream&lt;charT,traits&gt;&amp;
    noshowden1(std::basic_ostream&lt;charT,traits&gt;&amp; str);

template&lt;class charT, class traits&gt;
  std::basic_ostream&lt;charT,traits&gt;&amp;
    divalign(std::basic_ostream&lt;charT,traits&gt;&amp; str);

template&lt;class charT, class traits&gt;
  std::basic_ostream&lt;charT,traits&gt;&amp;
    nodivalign(std::basic_ostream&lt;charT,traits&gt;&amp; str);

template&lt;class charT&gt;
  <i>implementation-detail</i> setdiv(charT divsign);

template&lt;class charT, class traits&gt;
  std::basic_istream&lt;charT,traits&gt;&amp;
    operator&gt;&gt;(std::basic_istream&lt;charT,traits&gt;&amp; lhs, rational&amp; rhs);

template&lt;class charT, class traits&gt;
  std::basic_ostream&lt;charT,traits&gt;&amp;
    operator&lt;&lt;(std::basic_ostream&lt;charT,traits&gt;&amp; lhs, const rational&amp; rhs);

} // namespace rational
} // namespace experimental
} // namespace std
</pre>

<h3>[rational.class] Class <tt>rational</tt></h3>

<pre>
class rational {
public:
    typedef std::intmax_t int_type;

    rational() noexcept;

    rational(const rational&amp; rat) = default;

    explicit rational(char num) noexcept;
    explicit rational(signed char num) noexcept;
    explicit rational(unsigned char num) noexcept;
    explicit rational(char16_t num) noexcept;
    explicit rational(char32_t num) noexcept;
    explicit rational(wchar_t num) noexcept;
    explicit rational(short num) noexcept;
    explicit rational(unsigned short num) noexcept;
    explicit rational(int num) noexcept;
    explicit rational(unsigned num) noexcept;
    explicit rational(long num) noexcept;
    explicit rational(unsigned long num) noexcept;
    explicit rational(long long num) noexcept;
    explicit rational(unsigned long long num) noexcept;

    explicit rational(double val, double err = 1e-6);

    rational(int_type num, int_type den);

    ~rational() = default;

    rational&amp; operator=(const rational&amp; rat) = default;

    rational&amp; operator=(int_type num) noexcept;
    rational&amp; assign(int_type num, int_type den);

    void swap(rational&amp; rhs) noexcept;

    int_type numer() const noexcept;
    int_type denom() const noexcept;

    explicit operator bool() const noexcept;

    rational&amp; negate() noexcept;
    rational&amp; invert();

    rational&amp; operator++();
    rational&amp; operator--();

    rational operator++(int);
    rational operator--(int);

    rational&amp; operator+=(int_type rhs);
    rational&amp; operator-=(int_type rhs);
    rational&amp; operator*=(int_type rhs);
    rational&amp; operator/=(int_type rhs);

    rational&amp; operator+=(const rational&amp; rhs);
    rational&amp; operator-=(const rational&amp; rhs);
    rational&amp; operator*=(const rational&amp; rhs);
    rational&amp; operator/=(const rational&amp; rhs);
};
</pre>

<i>Class invariants:</i> all constructors and operators
shall eagerly normalize the value such that the numerator
and denominator have no common factors other than 1 and
the denominator is greater than zero.  If the numerator
is 0, the denominator shall be 1.

<h3>[rational.type] <tt>rational</tt> internal type:</h3>

<tt>typedef std::intmax_t int_type;</tt>
<blockquote>
This is the type that the <tt>rational</tt> class uses
internally for its numerator.  The denominator shall have
either the same type or an unsigned type that can hold
<nobr><tt>std::numeric_limits&lt;int_type&gt;::max()</tt>.</nobr>
</blockquote>

<h3>[rational.members] <tt>rational</tt> member functions:</h3>

<tt>rational() noexcept;</tt>
<blockquote>
<i>Effects:</i> Constructs a <tt>rational</tt> with a value of zero.
<p><i>Postcondition:</i> <tt>numer() == 0 &amp;&amp; denom() == 1</tt>.
</blockquote>

<p><tt>rational(const rational&amp; rat) = default;</tt>
<blockquote>
<i>Effects:</i> Constructs a <tt>rational</tt> with a value of <tt>rat</tt>.
<p><i>Postcondition:</i> <tt>numer() == rat.numer() &amp;&amp; denom() == rat.denom()</tt>.
</blockquote>

<p><tt>explicit rational(char num) noexcept;</tt>
<br><tt>explicit rational(signed char num) noexcept;</tt>
<br><tt>explicit rational(unsigned char num) noexcept;</tt>
<br><tt>explicit rational(char16_t num) noexcept;</tt>
<br><tt>explicit rational(char32_t num) noexcept;</tt>
<br><tt>explicit rational(wchar_t num) noexcept;</tt>
<br><tt>explicit rational(short num) noexcept;</tt>
<br><tt>explicit rational(unsigned short num) noexcept;</tt>
<br><tt>explicit rational(int num) noexcept;</tt>
<br><tt>explicit rational(unsigned num) noexcept;</tt>
<br><tt>explicit rational(long num) noexcept;</tt>
<br><tt>explicit rational(unsigned long num) noexcept;</tt>
<br><tt>explicit rational(long long num) noexcept;</tt>
<br><tt>explicit rational(unsigned long long num) noexcept;</tt>
<p><table border=0><tr><td bgcolor=lightgrey>
The intent is that <tt>rational</tt>s can be explicitly constructed from all the built-in
integer types except <tt>bool</tt>.
</td></tr></table>
<blockquote>
<i>Effects:</i> Constructs a <tt>rational</tt> with a value of <tt>num</tt>.
<p><i>Postcondition:</i> <tt>numer() == num &amp;&amp; denom() == 1</tt>.
<p><i>Recommended practice:</i> the implementation may provide additional
overloads for <tt>&lt;cstdint&gt;</tt> types that are not just
<tt>typedef</tt>s for fundamental integer types.
</blockquote>

<p><tt>explicit rational(double val, double err = 1e-6);</tt>
<p><table border=0><tr><td bgcolor=lightgrey>
Conversion from floating-point is probably a bad idea in general;
but it seems like one of those things that, when you need it, you <i>really</i>
need it; and folks who aren&rsquo;t experts in numerics might not know how to
write it.  How the conversion is done is a quality-of-implementation issue.
If numerics experts want a particular algorithm, they presumably know where to find it.
</td></tr></table>
<blockquote>
<p><i>Effects:</i> constructs a <tt>rational</tt> with a value approximately
equal to <tt>val</tt>.
<p><i>Postcondition:</i> the value of <tt>*this</tt> shall be in the range,
<tt>val</tt> <tt>*</tt> <tt>(1.0</tt> &plusmn; <tt>err)</tt>.
</blockquote>

<p><tt>rational(int_type num, int_type den);</tt>
<blockquote>
<i>Effects:</i> Constructs a <tt>rational</tt> given the specified numerator and denominator
and then enforces the class invariants.
<p><i>Postcondition:</i> <tt>*this</tt> <tt>==</tt> the mathematically correct <tt>num</tt>/<tt>den</tt>,
<tt>numer()</tt> and <tt>denom()</tt> have no common factors other than 1, and
<tt>denom()</tt> is greater than zero.
</blockquote>

<p><tt>~rational() = default;</tt>
<blockquote>
<i>Effects:</i> Destructs <tt>*this</tt>.
</blockquote>

<p><tt>rational&amp; operator=(int_type num) noexcept;</tt>
<blockquote>
<i>Effects:</i> Assigns <tt>num</tt> to <tt>*this</tt>.
<p><i>Postcondition:</i> <tt>numer() == num &amp;&amp; denom() == 1</tt>.
<p><i>Returns:</i> <tt>*this</tt>.
</blockquote>

<p><tt>rational&amp; assign(int_type num, int_type den);</tt>
<blockquote>
<i>Effects:</i> Assigns the specified numerator and denominator to <tt>*this</tt>
and then enforces the class invariants.
<p><i>Postcondition:</i> <tt>*this</tt> <tt>==</tt> the mathematically correct <tt>num</tt>/<tt>den</tt>,
<tt>numer()</tt> and <tt>denom()</tt> have no common factors other than 1, and
<tt>denom()</tt> is greater than zero.
<p><i>Returns:</i> <tt>*this</tt>.
</blockquote>

<p><tt>void swap(rational&amp; rhs) noexcept;</tt>
<blockquote>
<i>Effects:</i> Swaps <tt>*this</tt> and <tt>rhs</tt>.
<p><i>Postcondition:</i> <tt>*this</tt> <tt>==</tt> previous value of <tt>rhs</tt>;
<tt>rhs</tt> <tt>==</tt> previous value of <tt>*this</tt>.
</blockquote>

<p><tt>int_type numer() const noexcept;</tt>
<blockquote>
<i>Returns:</i> the value of the numerator.
</blockquote>

<p><tt>int_type denom() const noexcept;</tt>
<blockquote>
<i>Returns:</i> the value of the denominator.
</blockquote>

<p><tt>explicit operator bool() const noexcept;</tt>
<blockquote>
<i>Returns:</i> <tt>numer() != 0</tt>.
</blockquote>

<p><tt>rational&amp; negate() noexcept;</tt>
<blockquote>
<i>Effects:</i> changes the sign of the numerator.
<p><i>Returns:</i> <tt>*this</tt>.
</blockquote>

<p><tt>rational&amp; invert();</tt>
<blockquote>
<i>Effects:</i> swaps the numerator and denominator, changing their signs if necessary
to keep the denominator positive.
<p><i>Requires:</i> the numerator is non-zero and is not equal to the most negative
two&rsquo;s-complement value.
<p><i>Postcondition:</i> <tt>denom() &gt; 0</tt>.
<p><i>Returns:</i> <tt>*this</tt>.
</blockquote>

<h3>[rational.member.ops] <tt>rational</tt> member operators:</h3>

<p><tt>rational&amp; operator++();</tt>
<blockquote>
<i>Effects:</i> adds 1 to <tt>*this</tt> and stores the result in <tt>*this</tt>.
<p><i>Returns:</i> <tt>*this</tt>.
</blockquote>

<p><tt>rational&amp; operator--();</tt>
<blockquote>
<i>Effects:</i> subtracts 1 from <tt>*this</tt> and stores the result in <tt>*this</tt>.
<p><i>Returns:</i> <tt>*this</tt>.
</blockquote>

<p><tt>rational operator++(int);</tt>
<blockquote>
<i>Effects:</i> adds 1 to <tt>*this</tt> and stores the result in <tt>*this</tt>.
<p><i>Returns:</i> the value of <tt>*this</tt> before the addition.
</blockquote>

<p><tt>rational operator--(int);</tt>
<blockquote>
<i>Effects:</i> subtracts 1 from <tt>*this</tt> and stores the result in <tt>*this</tt>.
<p><i>Returns:</i> the value of <tt>*this</tt> before the subtraction.
</blockquote>

<p><tt>rational&amp; operator+=(int_type rhs);</tt>
<blockquote>
<i>Effects:</i> adds the integer value <tt>rhs</tt> to <tt>*this</tt> and stores the result in <tt>*this</tt>.
<p><i>Returns:</i> <tt>*this</tt>.
</blockquote>

<p><tt>rational&amp; operator-=(int_type rhs);</tt>
<blockquote>
<i>Effects:</i> subtracts the integer value <tt>rhs</tt> from <tt>*this</tt> and stores the result in <tt>*this</tt>.
<p><i>Returns:</i> <tt>*this</tt>.
</blockquote>

<p><tt>rational&amp; operator*=(int_type rhs);</tt>
<blockquote>
<i>Effects:</i> multiplies <tt>*this</tt> by the integer value <tt>rhs</tt> and stores the result,
reduced to lowest terms, in <tt>*this</tt>.
<p><i>Returns:</i> <tt>*this</tt>.
</blockquote>

<p><tt>rational&amp; operator/=(int_type rhs);</tt>
<blockquote>
<i>Effects:</i> divides <tt>*this</tt> by the integer value <tt>rhs</tt> and stores the result,
reduced to lowest terms, in <tt>*this</tt>.
<p><i>Returns:</i> <tt>*this</tt>.
</blockquote>

<p><tt>rational&amp; operator+=(const rational&amp; rhs);</tt>
<blockquote>
<i>Effects:</i> adds the rational value <tt>rhs</tt> to <tt>*this</tt> and stores the result,
reduced to lowest terms, in <tt>*this</tt>.
<p><i>Returns:</i> <tt>*this</tt>.
</blockquote>

<p><tt>rational&amp; operator-=(const rational&amp; rhs);</tt>
<blockquote>
<i>Effects:</i> subtracts the rational value <tt>rhs</tt> from <tt>*this</tt> and stores the result,
reduced to lowest terms, in <tt>*this</tt>.
<p><i>Returns:</i> <tt>*this</tt>.
</blockquote>

<p><tt>rational&amp; operator*=(const rational&amp; rhs);</tt>
<blockquote>
<i>Effects:</i> multiplies <tt>*this</tt> by the rational value <tt>rhs</tt> and stores the result,
reduced to lowest terms, in <tt>*this</tt>.
<p><i>Returns:</i> <tt>*this</tt>.
</blockquote>

<p><tt>rational&amp; operator/=(const rational&amp; rhs);</tt>
<blockquote>
<i>Effects:</i> divides <tt>*this</tt> by the rational value <tt>rhs</tt> and stores the result,
reduced to lowest terms, in <tt>*this</tt>.
<p><i>Returns:</i> <tt>*this</tt>.
</blockquote>

<h3>[rational.ops] <tt>rational</tt> non-member operations:</h3>

<p><tt>rational operator+(const rational&amp; val);</tt>
<blockquote>
<p><i>Returns:</i> <tt>rational(val)</tt>.
</blockquote>

<p><tt>rational operator-(const rational&amp; val);</tt>
<blockquote>
<p><i>Returns:</i> <tt>rational(-val.numer(), val.denom())</tt>.
</blockquote>

<p><tt>rational operator+(const rational&amp; lhs, const rational&amp; rhs);</tt>
<blockquote>
<p><i>Returns:</i> <tt>rational(lhs) += rhs</tt>.
</blockquote>

<p><tt>rational operator-(const rational&amp; lhs, const rational&amp; rhs);</tt>
<blockquote>
<p><i>Returns:</i> <tt>rational(lhs) -= rhs</tt>.
</blockquote>

<p><tt>rational operator*(const rational&amp; lhs, const rational&amp; rhs);</tt>
<blockquote>
<p><i>Returns:</i> <tt>rational(lhs) *= rhs</tt>.
</blockquote>

<p><tt>rational operator/(const rational&amp; lhs, const rational&amp; rhs);</tt>
<blockquote>
<p><i>Returns:</i> <tt>rational(lhs) /= rhs</tt>.
</blockquote>

<p><tt>rational operator+(const rational&amp; lhs, rational::int_type rhs);</tt>
<blockquote>
<p><i>Returns:</i> <tt>rational(lhs) += rhs</tt>.
</blockquote>

<p><tt>rational operator-(const rational&amp; lhs, rational::int_type rhs);</tt>
<blockquote>
<p><i>Returns:</i> <tt>rational(lhs) -= rhs</tt>.
</blockquote>

<p><tt>rational operator*(const rational&amp; lhs, rational::int_type rhs);</tt>
<blockquote>
<p><i>Returns:</i> <tt>rational(lhs) *= rhs</tt>.
</blockquote>

<p><tt>rational operator/(const rational&amp; lhs, rational::int_type rhs);</tt>
<blockquote>
<p><i>Returns:</i> <tt>rational(lhs) /= rhs</tt>.
</blockquote>

<p><tt>rational operator+(rational::int_type lhs, const rational&amp; rhs);</tt>
<blockquote>
<p><i>Returns:</i> <tt>rational(rhs) += lhs</tt>.
</blockquote>

<p><tt>rational operator-(rational::int_type lhs, const rational&amp; rhs);</tt>
<blockquote>
<p><i>Returns:</i> <tt>rational(-rhs) += lhs</tt>.
</blockquote>

<p><tt>rational operator*(rational::int_type lhs, const rational&amp; rhs);</tt>
<blockquote>
<p><i>Returns:</i> <tt>rational(rhs) *= lhs</tt>.
</blockquote>

<p><tt>rational operator/(rational::int_type lhs, const rational&amp; rhs);</tt>
<blockquote>
<p><i>Returns:</i> <tt>rational(rhs).invert() *= lhs</tt>.
</blockquote>

<p><tt>bool operator==(const rational&amp; lhs, const rational&amp; rhs);</tt>
<blockquote>
<p><i>Returns:</i> <tt>lhs.numer() == rhs.numer() &amp;&amp; lhs.denom() == rhs.denom()</tt>.
</blockquote>

<p><tt>bool operator!=(const rational&amp; lhs, const rational&amp; rhs);</tt>
<blockquote>
<p><i>Returns:</i> <tt>!(lhs == rhs)</tt>.
</blockquote>

<p><tt>bool operator&lt;(const rational&amp; lhs, const rational&amp; rhs);</tt>
<blockquote>
<p><i>Returns:</i> <tt>lhs.numer() * rhs.denom() < rhs.numer() * lhs.denom()</tt>.
<p><i>Recommended practice:</i> intermediate values should be reduced to
lowest terms to lessen the probability of overflow.
<br>[Example &mdash;
<pre>
  rational::int_type gcd = /* greatest common divisor of lhs.denom() and rhs.denom() */;
  rational::int_type lhd = lhs.denom() / gcd;
  rational::int_type rhd = rhs.denom() / gcd;
  return lhs.numer() * rhd &lt; rhs.numer() * lhd;
</pre>
&mdash; end example]
</blockquote>

<p><tt>bool operator&gt;(const rational&amp; lhs, const rational&amp; rhs);</tt>
<blockquote>
<p><i>Returns:</i> <tt>rhs &lt; lhs</tt>.
</blockquote>

<p><tt>bool operator&lt;=(const rational&amp; lhs, const rational&amp; rhs);</tt>
<blockquote>
<p><i>Returns:</i> <tt>!(rhs &lt; lhs)</tt>.
</blockquote>

<p><tt>bool operator&gt;=(const rational&amp; lhs, const rational&amp; rhs);</tt>
<blockquote>
<p><i>Returns:</i> <tt>!(lhs &lt; rhs)</tt>.
</blockquote>

<p><tt>bool operator==(const rational&amp; lhs, rational::int_type rhs);</tt>
<blockquote>
<p><i>Returns:</i> <tt>lhs.numer() == rhs &amp;&amp; lhs.denom() == 1</tt>.
</blockquote>

<p><tt>bool operator!=(const rational&amp; lhs, rational::int_type rhs);</tt>
<blockquote>
<p><i>Returns:</i> <tt>!(lhs == rhs)</tt>.
</blockquote>

<p><tt>bool operator&lt;(const rational&amp; lhs, rational::int_type rhs);</tt>
<blockquote>
<p><i>Returns:</i> <tt>lhs.numer() &lt; rhs * lhs.denom()</tt>.
</blockquote>

<p><tt>bool operator&gt;(const rational&amp; lhs, rational::int_type rhs);</tt>
<blockquote>
<p><i>Returns:</i> <tt>lhs.numer() &gt; rhs * lhs.denom()</tt>.
</blockquote>

<p><tt>bool operator&lt;=(const rational&amp; lhs, rational::int_type rhs);</tt>
<blockquote>
<p><i>Returns:</i> <tt>!(rhs &lt; lhs)</tt>.
</blockquote>

<p><tt>bool operator&gt;=(const rational&amp; lhs, rational::int_type rhs);</tt>
<blockquote>
<p><i>Returns:</i> <tt>!(lhs &lt; rhs)</tt>.
</blockquote>

<p><tt>bool operator==(rational::int_type lhs, const rational&amp; rhs);</tt>
<blockquote>
<p><i>Returns:</i> <tt>rhs == lhs</tt>.
</blockquote>

<p><tt>bool operator!=(rational::int_type lhs, const rational&amp; rhs);</tt>
<blockquote>
<p><i>Returns:</i> <tt>rhs != lhs</tt>.
</blockquote>

<p><tt>bool operator&lt;(rational::int_type lhs, const rational&amp; rhs);</tt>
<blockquote>
<p><i>Returns:</i> <tt>rhs &gt; lhs</tt>.
</blockquote>

<p><tt>bool operator&gt;(rational::int_type lhs, const rational&amp; rhs);</tt>
<blockquote>
<p><i>Returns:</i> <tt>rhs &lt; lhs</tt>.
</blockquote>

<p><tt>bool operator&lt;=(rational::int_type lhs, const rational&amp; rhs);</tt>
<blockquote>
<p><i>Returns:</i> <tt>rhs &gt;= lhs</tt>.
</blockquote>

<p><tt>bool operator&gt;=(rational::int_type lhs, const rational&amp; rhs);</tt>
<blockquote>
<p><i>Returns:</i> <tt>rhs &lt;= lhs</tt>.
</blockquote>

<h3>[rational.conv] <tt>rational</tt> numeric conversions:</h3>

<p><tt>rational::int_type floor(const rational&amp; val);</tt>
<blockquote>
<p><i>Returns:</i> the most positive integer not greater than <tt>val</tt>.
</blockquote>

<p><tt>rational::int_type ceil(const rational&amp; val);</tt>
<blockquote>
<p><i>Returns:</i> the most negative integer not less than <tt>val</tt>.
</blockquote>

<p><tt>rational::int_type trunc(const rational&amp; val);</tt>
<blockquote>
<p><i>Returns:</i> the integer part of <tt>val</tt> truncated toward zero.
</blockquote>

<pre>
enum rounding_mode
{
    nearest_even, nearest_odd,
    toward_pos_inf, toward_neg_inf,
    toward_zero, away_from_zero
};
rational::int_type nearest(const rational&amp; val, rounding_mode mode = nearest_even);
</pre>
<blockquote>
<p><i>Returns:</i> the integer nearest in value to <tt>val</tt>.
If <tt>val.denom() == 2</tt>, the returned value shall be rounded
as specified by <tt>mode</tt>.
</blockquote>

<h3>[rational.swap] <tt>rational</tt> swap:</h3>

<p><tt>void swap(rational&amp; lhs, rational&amp; rhs) noexcept;</tt>
<blockquote>
<p><i>Effects:</i> <tt>lhs.swap(rhs)</tt>.
</blockquote>

<h3>[rational.manip] I/O manipulators that apply to <tt>rational</tt> objects:</h3>

<pre>
template&lt;class charT, class traits&gt;
  std::basic_ostream&lt;charT,traits&gt;&amp;
    showden1(std::basic_ostream&lt;charT,traits&gt;&amp; str);

template&lt;class charT, class traits&gt;
  std::basic_ostream&lt;charT,traits&gt;&amp;
    noshowden1(std::basic_ostream&lt;charT,traits&gt;&amp; str);
</pre>
<blockquote>
These output manipulators control whether a denominator equal to 1 is written.
If <tt>noshowden1</tt> is in effect and the rational&rsquo;s
denominator equals 1, the output shall be just the numerator written
as an ordinary <tt>rational::int_type</tt>.
The default is <tt>noshowden1</tt>.
</blockquote>

<pre>
template&lt;class charT, class traits&gt;
  std::basic_ostream&lt;charT,traits&gt;&amp;
    divalign(std::basic_ostream&lt;charT,traits&gt;&amp; str);

template&lt;class charT, class traits&gt;
  std::basic_ostream&lt;charT,traits&gt;&amp;
    nodivalign(std::basic_ostream&lt;charT,traits&gt;&amp; str);
</pre>
<blockquote>
These output manipulators specify whether the stream&rsquo;s width
and <tt>adjustfield</tt> flags affect the numerator
only (<tt>divalign</tt>) or the whole fraction (<tt>nodivalign</tt>).
The former is intended for printing fractions in columns by aligning
the division signs.  The default is <tt>nodivalign</tt>.
<p>[Example &mdash;
<pre>
    rational r1(5);
    rational r2(24, 17);
    cout &lt;&lt; r1 &lt;&lt; '\n'
         &lt;&lt; r2 &lt;&lt; '\n'
         &lt;&lt; showden1
         &lt;&lt; setfill('*')
         &lt;&lt; setw(6) &lt;&lt; r1 &lt;&lt; '\n'
         &lt;&lt; setw(6) &lt;&lt; r2 &lt;&lt; '\n'
         &lt;&lt; divalign
         &lt;&lt; setw(6) &lt;&lt; r1 &lt;&lt; '\n'
         &lt;&lt; setw(6) &lt;&lt; r2 &lt;&lt; '\n'
         &lt;&lt; left &lt;&lt; setfill(' ') &lt;&lt; setw(6) &lt;&lt; r2
         &lt;&lt; " (You might want to avoid left with divalign.)\n";
</pre>
yields the output:
<pre>
    5
    24/17
    ***5/1
    *24/17
    *****5/1
    ****24/17
    24    /17 (You might want to avoid left with divalign.)
</pre>
&mdash; end example]
</blockquote>

<pre>
template&lt;class charT&gt;
  <i>implementation-detail</i> setdiv(charT divsign);
</pre>
<blockquote>
This I/O manipulator causes <tt>divsign</tt> to be used for the division sign.
The default is <nobr><i>stream</i><tt>.widen('/')</tt>.</nobr>
</blockquote>

<h3>[rational.io] I/O operators that apply to <tt>rational</tt> objects:</h3>

<pre>
template&lt;class charT, class traits&gt;
  std::basic_istream&lt;charT,traits&gt;&amp;
    operator&gt;&gt;(std::basic_istream&lt;charT,traits&gt;&amp; lhs, rational&amp; rhs);
</pre>
<blockquote>
The extraction operator reads an integer value which it takes to be a
numerator, and if that is immediately followed by a division sign, reads another integer
value which it takes to be a denominator.  If no division sign immediately
follows the numerator, the denominator shall be assumed to be 1.

<p>If the operator reads a value of zero when expecting a denominator,
it shall set the stream&rsquo;s <tt>failbit</tt>.  If an
<tt>ios_base::failure</tt> exception is thrown, or if the stream is not
<nobr><tt>good()</tt></nobr> when the operator returns, <tt>rhs</tt> shall be untouched.

<p>If the operator is successful, it shall have enforced the class invariants.

<p>The stream&rsquo;s <tt>locale</tt> and all its format flags except
<tt>skipws</tt> shall apply separately to the numerator and the denominator.
<tt>skipws</tt> shall apply to the numerator only.[footnote]

<p>[footnote] Thus, if a denominator
is present, the division sign must immediately follow the numerator, and
the denominator must immediately follow the division sign, without any
intervening characters including whitespace.
</blockquote>

<pre>
template&lt;class charT, class traits&gt;
  std::basic_ostream&lt;charT,traits&gt;&amp;
    operator&lt;&lt;(std::basic_ostream&lt;charT,traits&gt;&amp; lhs, const rational&amp; rhs);
</pre>
<blockquote>
The insertion operator shall write a <tt>rational</tt> to the specified output
stream; and the numerator and denominator shall be written in whatever
format is appropriate given the stream&rsquo;s flags and <tt>locale</tt>.
The <tt>showpos</tt> and <tt>showbase</tt> flags shall affect the numerator only.
</blockquote>

<h3>[rational.over] Additional overloads:</h3>

<p><tt>rational abs(const rational&amp; val);</tt>
<blockquote>
<i>Returns:</i> <tt>rational(val)</tt> if <tt>val</tt> <tt>&gt;=</tt> 0;
otherwise <tt>-val</tt>.
</blockquote>

<p><tt>rational reciprocal(const rational&amp; val);</tt>
<blockquote>
<i>Returns:</i> <tt>rational(val).invert()</tt>.
</blockquote>

<p><tt>rational ipow(const rational&amp; val, int exp);</tt>
<p><table border=0><tr><td bgcolor=lightgrey>
This is intended to be analagous to <tt>std::pow(double,double)</tt>.
The name, &ldquo;<tt>ipow</tt>&rdquo;, is intended to draw attention
to the integer exponent requirement.
</td></tr></table>
<blockquote>
<i>Returns:</i> <tt>rational(1)</tt> if <tt>exp</tt> <tt>==</tt> 0;
otherwise <tt>val<sup>exp</sup></tt>.
<p><i>Requires:</i> <tt>val != 0 || exp >= 0</tt>.
<p><i>Remarks:</i> the exponent must be an integer since raising
to a non-integer power yields an irrational value in general.
</blockquote>

<p><tt>rational fmod(const rational&amp; dividend, const rational&amp; divisor);</tt>
<p><table border=0><tr><td bgcolor=lightgrey>
This is intended to be analagous to <tt>std::fmod(double,double)</tt>.
</td></tr></table>
<blockquote>
<i>Returns:</i> <tt>dividend - divisor * trunc(dividend / divisor)</tt>.
</blockquote>

<pre>
rational remainder(const rational&amp; dividend, const rational&amp; divisor,
                   rounding_mode mode = nearest_even);
</pre>
<table border=0><tr><td bgcolor=lightgrey>
This is intended to be analagous to <tt>std::remainder(double,double)</tt>.
</td></tr></table>
<blockquote>
<i>Returns:</i> <tt>dividend - divisor * nearest(dividend / divisor, mode)</tt>.
</blockquote>

<pre>
template&lt;class intT&gt;
  rational modf(const rational&amp; val, intT* intptr);
</pre>
<table border=0><tr><td bgcolor=lightgrey>
This is intended to be analagous to <tt>std::modf(double,double*)</tt>.
</td></tr></table>
<blockquote>
<i>Effects:</i> if <tt>intptr</tt> is not a null pointer,
<tt>*intptr</tt> shall be assigned <tt>trunc(val)</tt>.
<p><i>Returns:</i> <tt>val - trunc(val)</tt>.
</blockquote>

<p><tt>rational modf(const rational&amp; val);</tt>
<p><table border=0><tr><td bgcolor=lightgrey>
This non-template one-argument overload is intended for users
who want just the fractional part and don&rsquo;t want to bother
passing a null pointer to a template argument.
</td></tr></table>
<blockquote>
<i>Returns:</i> <tt>val - trunc(val)</tt>.
</blockquote>

<pre>
template&lt;class intT&gt;
  rational remquo(const rational&amp; dividend, const rational&amp; divisor, intT* intptr,
                  rounding_mode mode = nearest_even);
</pre>
<table border=0><tr><td bgcolor=lightgrey>
This is intended to be analagous to <tt>std::remquo(double,double,int*)</tt>.
</td></tr></table>
<blockquote>
<i>Effects:</i> if <tt>intptr</tt> is not a null pointer,
<tt>*intptr</tt> shall be assigned <tt>nearest(dividend / divisor, mode)</tt>.
<p><i>Returns:</i> <tt>remainder(dividend, divisor, mode)</tt>.
</blockquote>

<p><hr size=8>
All suggestions and corrections will be welcome; all flames will be amusing.
<br>Mail to stdbill dot h at pobox dot com.
</body>
</html>
