<html>
<head>
<title>N3611 - A Rational Number Library for C++</title>
</head>
<body>
<table border=0>
<tr>
  <td><b>Doc No:</b></td>
  <td>N3611</td>
</tr>
<tr>
  <td><b>Date:</b></td>
  <td>2013-03-15</td>
</tr>
<tr>
  <td><b>Reply to:</b>&nbsp;</td>
  <td>Bill Seymour, &lt;stdbill<tt>.</tt>h<sup>@</sup>pobox<tt>.</tt>com&gt;</td>
</tr>
</table>

<!--
Lawrence Crowl, crowl@google.com, Lawrence@Crowl.org
Pete Becker, pete@versatilecoding.com
-->

<center>
<h2>A Rational Number Library for C++</h2>
<h3>Bill Seymour<br>2013-03-15</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).

<p>Revision history:
<ul>
<li><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3363.html">N3363</a> &ndash; post-Kona (original)
<li><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3414.html">N3414</a> &ndash; pre-Portland
<li><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n389.html">N3489</a> &ndash; post-Portland
<li>N3611 &ndash; this paper
</ul>

Many thanks to Daniel Kr&uuml;gler for several excellent suggestions to get from N3363 to N3414.

<p>This paper reflects several changes to N3414 suggested by the Numerics Study Group
<nobr>(SG-6)</nobr> in Portland.  These are:
<ul>
<li>replace all the one-argument constructors from integer types with just one taking Pete Becker&rsquo;s
    <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3417.html"><tt>seminumerical::integer</tt></a>
    as an argument.
<li>conversion from floating-point values can be exact.
<li>remove the <tt>fmod</tt>, <tt>remainder</tt> and <tt>remquo</tt> functions.
<li>change the name of the <tt>ipow</tt> function to just <tt>pow</tt> and
    fail to compile for non-integer exponents.
</ul>

<p>A change suggested by <nobr>SG-6</nobr> but not yet incorporated into this paper
is using for the second argument to the <a href="#nearest"><tt>nearest</tt> function</a>
the rounding modes from Lawrence Crowl&rsquo;s
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3352.html#basic_operations">N3352,
<i>C++ Binary Fixed-Point Arithmetic</i>, Basic Operations</a>.  Lawrence said that he
will break that out into a separate paper.  That change will probably appear
in this paper&rsquo;s post-Bristol revision.

<p>One additional change, not suggested by <nobr>SG-6</nobr> but mentioned in N3414,
is having a mechanism for temporarily turning off normalization as suggested in
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1718.pdf">N1718</a>.

<p>N3489 asked whether the comparison operators should normalize the fraction
so that they always give the right answer.  Actually, this matters only for the
<nobr><tt>==</tt></nobr> operators; and they can easily be written to work
correctly if they know whether the <tt>rational</tt> is currently being
normalized.  To facilitate that, the <nobr><tt>normalizing()</tt></nobr>
member function was added.  (Note that this can&rsquo;t be just a no-argument
overload of the existing <nobr><tt>normalize()</tt></nobr> member function
since that function&rsquo;s only argument defaults.)

<p>Also, I&rsquo;ve decided that I like the <tt>seminumerical</tt> namespace in Pete Becker&rsquo;s
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3417.html">N3417</a>.

<p><i>Question:</i>  do we want conversion from fixed- and/or floating-point
decimals?  Fixed-point binary?  I think all of them; but it&rsquo;s not clear yet
what will come out of <nobr>SG-6</nobr> in this regard.

<p><i>Question:</i>  do we want rational literals?  I think not in general;
and I echo the rationale in Pete Becker&rsquo;s Open issue 7
in <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3417.html">N3417</a>
(they wouldn&rsquo;t be <tt>constexpr</tt>).  On the other hand, if Pete&rsquo;s
<tt>integer</tt> implements a small-integer optimization and has <tt>constexpr</tt>
conversions from fundamental integer types, then maybe we could have literals for
those rationals whose numerator and denominator can be represented in the fundamental types.

<p><i>Issue:</i>  I still need to add move semantics.

<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>
namespace std {
namespace seminumerical {

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, const integer&amp; rhs);
rational operator-(const rational&amp; lhs, const integer&amp; rhs);
rational operator*(const rational&amp; lhs, const integer&amp; rhs);
rational operator/(const rational&amp; lhs, const integer&amp; rhs);

rational operator+(const integer&amp; lhs, const rational&amp; rhs);
rational operator-(const integer&amp; lhs, const rational&amp; rhs);
rational operator*(const integer&amp; lhs, const rational&amp; rhs);
rational operator/(const integer&amp; 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, const integer&amp; rhs);
bool operator!=(const rational&amp; lhs, const integer&amp; rhs);
bool operator&lt; (const rational&amp; lhs, const integer&amp; rhs);
bool operator&gt; (const rational&amp; lhs, const integer&amp; rhs);
bool operator&lt;=(const rational&amp; lhs, const integer&amp; rhs);
bool operator&gt;=(const rational&amp; lhs, const integer&amp; rhs);

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

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

integer floor(const rational&amp; val);
integer ceil (const rational&amp; val);
integer trunc(const rational&amp; val);

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

integer round(const rational&amp; val);

rational abs(const rational&amp; val);

rational reciprocal(const rational&amp; val);

template&lt;class T&gt; rational pow(const rational&amp;, T) = delete;
template&lt;&gt; rational pow(const rational&amp; val, const integer&amp; exp);

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

rational modf(const rational&amp; val);

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 seminumerical
} // namespace std
</pre>

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

<p><tt>class rational {</tt><br>
<tt>&nbsp;&nbsp;&nbsp;&nbsp;bool do_norm;&nbsp;//&nbsp;</tt><i>exposition only</i>
<pre>
public:
    rational() noexcept;

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

    explicit rational(float num);
    explicit rational(double num);
    explicit rational(long double num);

    explicit rational(const integer&amp; num);

    rational(const integer&amp; num, const integer&amp; den);

    ~rational() = default;

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

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

    void swap(rational&amp; rhs) noexcept;

    void normalize(bool norm = true) noexcept;
    bool normalizing() const noexcept;

    const integer&amp; numer() const noexcept;
    const integer&amp; 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+=(const integer&amp; rhs);
    rational&amp; operator-=(const integer&amp; rhs);
    rational&amp; operator*=(const integer&amp; rhs);
    rational&amp; operator/=(const integer&amp; 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>

The numerator and denominator shall be stored internally in a
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3417.html">std::seminumerical::integer</a>.

<p><i>Class invariants:</i> all constructors except the copy constructor
shall set <tt>do_norm</tt> to <tt>true</tt>; and if <tt>do_norm</tt>
is <tt>true</tt>, all member functions that can mutate the value 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.

<p>[<i>Note:</i> given the as-if rule, the copy constructor and copy-assignment operator don&rsquo;t
actually need to do any normalization; they just copy the numerator, denominator
and <tt>do_norm</tt> flag verbatim.  If <tt>do_norm</tt> is <tt>true</tt>,
then presumably the value was already normalized anyway. &mdash; <i>end note</i>]

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

<tt>typedef <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3417.html">integer</a> int_type;</tt>
<blockquote>
This is the type that the <tt>rational</tt> class uses
internally for its numerator and denominator.
</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() &amp;&amp; do_norm == rat.do_norm</tt>.
</blockquote>

<p><tt>explicit rational(const integer&amp; num);</tt>
<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>.
</blockquote>

<p><tt>explicit rational(float val);</tt>
<br><tt>explicit rational(double val);</tt>
<br><tt>explicit rational(long double val);</tt>
<blockquote>
<p><i>Effects:</i> constructs a <tt>rational</tt> with a value equal to <tt>val</tt>.
<p><i>Postcondition:</i>
<tt>static_cast&lt;decltype(val)&gt;(numer()) / static_cast&lt;decltype(val)&gt;(denom()) == val</tt>.
</blockquote>

<p><tt>rational(const integer&amp; num, const integer&amp; den);</tt>
<blockquote>
<i>Requires:</i> <tt>den != 0</tt>
<p><i>Effects:</i> Constructs a <tt>rational</tt> given the specified numerator and denominator.
</blockquote>

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

<p><tt>rational&amp; operator=(const rational&amp; rhs) = default;</tt>
<blockquote>
<i>Effects:</i> Assigns <tt>rhs</tt> to <tt>*this</tt>.
<p><i>Postcondition:</i> <tt>numer() == rhs.numer() &amp;&amp; denom() == rhs.denom() &amp;&amp; do_norm == rhs.do_norm</tt>.
<p><i>Returns:</i> <tt>*this</tt>.
</blockquote>

<p><tt>rational&amp; operator=(const integer&amp; 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(const integer&amp; num, const integer&amp; den);</tt>
<blockquote>
<i>Requires:</i> <tt>den != 0</tt>
<p><i>Effects:</i> Assigns the specified numerator and denominator to <tt>*this</tt>.
<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>void normalize(bool norm = true) noexcept;</tt>
<blockquote>
<i>Effects:</i> sets <tt>do_norm</tt> to <tt>norm</tt>.
<p><i>Postcondition:</i> if <tt>norm</tt> is <tt>true</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>bool normalizing() const noexcept;</tt>
<blockquote>
<i>Returns:</i> <tt>do_norm</tt>.
</blockquote>

<p><tt>const integer&amp; numer() const noexcept;</tt>
<blockquote>
<i>Returns:</i> a <tt>const</tt> reference to the numerator.
</blockquote>

<p><tt>const integer&amp; denom() const noexcept;</tt>
<blockquote>
<i>Returns:</i> a <tt>const</tt> reference to 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.
<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+=(const integer&amp; 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-=(const integer&amp; 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*=(const integer&amp; rhs);</tt>
<blockquote>
<i>Effects:</i> multiplies <tt>*this</tt> by the integer value <tt>rhs</tt> and stores the result
in <tt>*this</tt>.
<p><i>Returns:</i> <tt>*this</tt>.
</blockquote>

<p><tt>rational&amp; operator/=(const integer&amp; rhs);</tt>
<blockquote>
<i>Effects:</i> divides <tt>*this</tt> by the integer value <tt>rhs</tt> and stores the result
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
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
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
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
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, const integer&amp; rhs);</tt>
<blockquote>
<p><i>Returns:</i> <tt>rational(lhs) += rhs</tt>.
</blockquote>

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

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

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

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

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

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

<p><tt>rational operator/(const integer&amp; 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>.
</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, const integer&amp; 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, const integer&amp; rhs);</tt>
<blockquote>
<p><i>Returns:</i> <tt>!(lhs == rhs)</tt>.
</blockquote>

<p><tt>bool operator&lt;(const rational&amp; lhs, const integer&amp; 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, const integer&amp; 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, const integer&amp; rhs);</tt>
<blockquote>
<p><i>Returns:</i> <tt>!(rhs &lt; lhs)</tt>.
</blockquote>

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

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

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

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

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

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

<p><tt>bool operator&gt;=(const integer&amp; 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>integer floor(const rational&amp; val);</tt>
<blockquote>
<p><i>Returns:</i> the most positive integer not greater than <tt>val</tt>.
</blockquote>

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

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

<a name="nearest"><pre>
enum rounding_mode
{
    nearest_even, nearest_odd,
    toward_pos_inf, toward_neg_inf,
    toward_zero, away_from_zero
};
integer nearest(const rational&amp; val, rounding_mode mode = nearest_even);
</pre></a>
<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>

<pre>
integer round(const rational&amp; val);
</pre>
<blockquote>
<p><i>Returns:</i> <tt>nearest(val, away_from_zero)</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>integer</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 default is <tt>nodivalign</tt>.
[<i>Note:</i> <tt>divalign</tt> is intended for printing fractions in columns by aligning
the division signs. &mdash; <i>end note</i>]

<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>

<pre>
template&lt;class T&gt; rational pow(const rational&amp;, T) = delete;
template&lt;&gt; rational pow(const rational&amp; val, const integer&amp; exp);
</pre>
<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>

<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>

<p><hr size=8>
All suggestions and corrections will be welcome; all flames will be amusing.
<br>Bill Seymour, &lt;stdbill<tt>.</tt>h<sup>@</sup>pobox<tt>.</tt>com&gt;.
</body>
</html>
 