<html>
<head>
<title>N3489 - A Rational Number Library for C++</title>
</head>
<body>
<table border=0>
<tr>
  <td><b>Doc No:</b></td>
  <td>N3489 = 12-0179</td>
</tr>
<tr>
  <td><b>Date:</b></td>
  <td>2012-10-31</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>

<center>
<h2>A Rational Number Library for C++</h2>
<h3>Bill Seymour<br>2012-10-31</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 a rewrite of
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3414.html">N3414</a>.
Many thanks to Daniel Kr&uuml;gler for several excellent suggestions to get from
the first version, N3363, to N3414.

<p>This paper reflects several changes to N3414 suggested by the Numerics Study Group (SG-6)
in Portland.  These are:
<ul>
<li>replace all the one-argument constructors from integer types with just one
    taking a <tt>rational::int_type</tt>.
<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>One additional change, not suggested by SG-6 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>.
(<i>Issue:</i> should the comparison operators normalize the fraction so that they
always give the right answer?)

<p>A change suggested by SG-6 but not yet incorporated into this paper
is using the rounding modes from Lawrence Crowl&rsquo;s binary fixed-point paper
for the second argument to the <tt>nearest</tt> function.  Lawrence said that he
will break that out into a separate paper.  That change will probably appear
in the pre-Bristol <tt>rational</tt>.

<!--
<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>
namespace std {
namespace experimental { // subnamespace for TRs 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, const rational::int_type&amp; rhs);
rational operator-(const rational&amp; lhs, const rational::int_type&amp; rhs);
rational operator*(const rational&amp; lhs, const rational::int_type&amp; rhs);
rational operator/(const rational&amp; lhs, const rational::int_type&amp; rhs);

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

bool operator==(const rational::int_type&amp; lhs, const rational&amp; rhs);
bool operator!=(const rational::int_type&amp; lhs, const rational&amp; rhs);
bool operator&lt; (const rational::int_type&amp; lhs, const rational&amp; rhs);
bool operator&gt; (const rational::int_type&amp; lhs, const rational&amp; rhs);
bool operator&lt;=(const rational::int_type&amp; lhs, const rational&amp; rhs);
bool operator&gt;=(const rational::int_type&amp; 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::int_type 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 rational::int_type&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 rational
} // namespace experimental
} // namespace std
</pre>

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

<pre>
class rational {
    bool do_norm;  /* exposition only */

public:
    typedef <i>implementation-detail</i> int_type;

    rational() noexcept;

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

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

    explicit rational(const int_type&amp; num);

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

    ~rational() = default;

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

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

    void swap(rational&amp; rhs) noexcept;

    void normalize(bool norm = true);

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

<i>Class invariants:</i> all constructors
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 <i>implementation-detail</i> int_type;</tt>
<blockquote>
This is the type that the <tt>rational</tt> class uses
internally for its numerator and denominator.  It shall be
a signed unbounded integer type.
</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 int_type&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 num) noexcept;</tt>
<br><tt>explicit rational(double num) noexcept;</tt>
<br><tt>explicit rational(long double num) noexcept;</tt>
<blockquote>
<p><i>Effects:</i> constructs a <tt>rational</tt> with a value equal to num.
<p><i>Postcondition:</i>
<tt>static_cast&lt;decltype(num)&gt;(numer()) / static_cast&lt;decltype(num)&gt;(denom()) == num</tt>.
</blockquote>

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

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

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

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

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

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

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

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

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

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

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

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

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

<p><tt>bool operator&gt;=(const rational::int_type&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>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>

<pre>
rational::int_type 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>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 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 rational::int_type&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>
 