<html>
<head>
<title>P1438R0 - A Rational Number Library for C++</title>
</head>
<body>
<table border=0>
<tr>
  <td><b>Doc No:</b></td>
  <td>P1438R0</td>
</tr>
<tr>
  <td><b>Date:</b></td>
  <td>2019-01-19</td>
</tr>
<tr>
  <td><b>Author:</b>&nbsp;</td>
  <td>Bill Seymour</td>
</tr>
<tr>
  <td><b>Reply to:</b>&nbsp;</td>
  <td>stdbill<tt>.</tt>h<sup>@</sup>pobox<tt>.</tt>com</td>
</tr>
<tr>
  <td><b>Audience:</b></td>
  <td>SG6 (Numerics)</td>
</tr>
</table>

<center>
<h2>A Rational Number Library for C++</h2>
<h3>Bill Seymour<br>2019-01-19</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>Because almost every operation on rational numbers requires multiplication
behind the scenes, numerators and denominators can become quite large in a hurry,
easily overflowing any fundamental integer type; so this paper requires
that the numerator and denominator be stored internally in an unlimited-precision
integer such as the one suggested by Pete Becker in
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4038.html">N4038</a>.

<p><hr size=8><h2>Revision history:</h2>
<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/n3489.html">N3489</a> &ndash; post-Portland
<li><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3611.html">N3611</a> &ndash; pre-Bristol
<li>DnnnnR0 &ndash; this paper
</ul>

<table border=0><tr><td bgcolor=yellow>
It just occurred to me that this never made it into a mailing.  This paper contains
changes that SG6 suggested at the last Kona meeting.  It&rsquo;s the latest and greatest.
I don&rsquo;t anticipate needing committee time in the 2019 Kona meeting.
</td></tr></table>

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

<p>Thanks also to Lawrence Crowl for his excellent suggestions for this revision.

<p>As suggested in Bristol, normalization is now required only when the numerator and denominator
become separately visible as a result of calling the <nobr><tt>numer()</tt></nobr> and <nobr><tt>denom()</tt></nobr>
observers or the <tt>ostream</tt> insertion operator, or when the user explicitly requests it
by calling the <nobr><tt>normalize()</tt></nobr> member function.  The implementation is permitted to reduce
the fraction to lowest terms at other times for efficiency, but that&rsquo;s a quality-of-implementation issue.

<p>The rounding mode argument to the <tt><a href="#nearest">nearest</a></tt> function now has the
<nobr><tt>enum</tt>&nbsp;<tt>class</tt>&nbsp;<tt>rounding</tt></nobr> type in
Lawrence Crowl&rsquo;s <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0105r1.html">P0105R1</a>.

<p>The <tt><a href="http://www.amazon.com/Art-Computer-Programming-Volume-Seminumerical/dp/0201896842">seminumeric</a></tt>
namespace is a placeholder for whatever namespace will appear in the TS.

<p><hr size=8><h2>Questions:</h2>

<ol>
<li>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><li>Do we want rational literals?  I think not;
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/2014/n4038.html">N4038</a>
(they wouldn&rsquo;t be <tt>constexpr</tt>).
</ol>

<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 {
namespace seminumeric {

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);
integer nearest(const rational&amp; val, <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0105r1.html#RoundMode">rounding</a> mode = rounding::tie_to_even);
integer round(const rational&amp; val);

rational abs(const rational&amp; val);

rational reciprocal(const rational&amp; val);

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; stream);

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

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

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

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

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

<tt>class rational {</tt><br>
<tt>&nbsp;&nbsp;&nbsp;&nbsp;<a href="#norm">mutable</a> <a href="#int">integer</a> this_num, this_den; //</tt> <i>exposition only</i>
<pre>
public:
    rational() noexcept;

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

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

    explicit rational(const integer&amp; num);
    explicit rational(integer&amp;&amp; num) noexcept;

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

    ~rational();

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

    rational&amp; operator=(const integer&amp; num);
    rational&amp; operator=(integer&amp;&amp; num);

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

    void swap(rational&amp; rhs) noexcept;

    void normalize() <a href="#norm">const</a>;

    integer numer() const;
    integer denom() const;

    explicit operator bool() const noexcept;

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

    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>

<a name="int">The numerator and denominator shall be stored internally</a> in a
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4038.html">std::experimental::seminumeric::integer</a>.

<p>The internal representation shall be reduced to lowest terms
(the numerator and denominator shall have no common factor other than 1
and the denominator shall be greater than zero):
<ul>
<li>as a result of calling the <tt>normalize()</tt> member function, and
<li>when the numerator and/or denominator become separately visible
    (as a result of calling the <tt>numer()</tt> and <tt>denom()</tt> observers
    or the <tt>ostream</tt> insertion operator).
</ul>
The implementation may also normalize the representation at other times for the sake of efficiency.

<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.
</blockquote>

<p><tt>rational(const rational&amp; rat);</tt>
<br><tt>rational(rational&amp;&amp; rat);</tt>
<blockquote>
<i>Effects:</i> Constructs a <tt>rational</tt> with a value of <tt>rat</tt>.
</blockquote>

<p><tt>explicit rational(const integer&amp; num);</tt>
<br><tt>explicit rational(integer&amp;&amp; num);</tt>
<blockquote>
<i>Effects:</i> Constructs a <tt>rational</tt> with a value of <tt>num</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>.
</blockquote>

<p><tt>rational(const integer&amp; num, const integer&amp; den);</tt>
<br><tt>rational(integer&amp;&amp; num, integer&amp;&amp; den) noexcept;</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();</tt>
<blockquote>
<i>Effects:</i> Destructs <tt>*this</tt>.
</blockquote>

<p><tt>rational&amp; operator=(const rational&amp; rhs);</tt>
<br><tt>rational&amp; operator=(rational&amp;&amp; rhs) noexcept;</tt>
<blockquote>
<i>Effects:</i> Assigns <tt>rhs</tt> to <tt>*this</tt>.
<p><i>Returns:</i> <tt>*this</tt>.
</blockquote>

<p><tt>rational&amp; operator=(const integer&amp; num);</tt>
<br><tt>rational&amp; operator=(integer&amp;&amp; num);</tt>
<blockquote>
<i>Effects:</i> Assigns <tt>num</tt> to <tt>*this</tt>.
<p><i>Returns:</i> <tt>*this</tt>.
</blockquote>

<p><tt>rational&amp; assign(const integer&amp; num, const integer&amp; den);</tt>
<br><tt>rational&amp; assign(integer&amp;&amp; num, integer&amp;&amp; den) noexcept;</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>.
</blockquote>

<p><a name="norm"><tt>void normalize() const;</tt>[footnote]</a>
<blockquote>
<i>Effects:</i> reduces the fraction to lowest terms.
<p><i>Postcondition:</i> <tt>numer()</tt> and <tt>denom()</tt> have no common factors other than 1,
and <tt>denom()</tt> is greater than zero.
<p>[footnote]This is a conceptually <tt>const</tt> member function because it&rsquo;s used by
the <tt>numer()</tt> and <tt>denom()</tt> observers and the <tt>ostream</tt>
insertion operator.  Note that the observable value of <nobr><tt>*this</tt></nobr>
doesn&rsquo;t change, which is consistent with the meaning of <tt>const</tt>.
</blockquote>

<p><tt>integer numer() const;</tt>
<blockquote>
<i>Effects:</i> reduces the fraction to lowest terms as if by calling <tt>normalize()</tt>.
<p><i>Returns:</i> the numerator by value.
</blockquote>

<p><tt>integer denom() const;</tt>
<blockquote>
<i>Effects:</i> reduces the fraction to lowest terms as if by calling <tt>normalize()</tt>.
<p><i>Returns:</i> the denominator by value.
</blockquote>

<p><tt>explicit operator bool() const noexcept;</tt>
<blockquote>
<i>Returns:</i> as if <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() noexept;</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>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>Requires:</i> <tt>rhs != 0</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>Requires:</i> <tt>rhs != 0</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).negate()</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>
<i>Requires:</i> <tt>rhs != 0</tt>.
<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>
<i>Requires:</i> <tt>rhs != 0</tt>.
<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).negate() += 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>
<i>Requires:</i> <tt>rhs != 0</tt>.
<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> as if <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> as if <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>lhs &lt; rhs || lhs == rhs</tt>.
</blockquote>

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

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

<p><tt>bool operator&gt;=(const rational&amp; lhs, const integer&amp; rhs);</tt>
<blockquote>
<p><i>Returns:</i> <tt>lhs &gt; rhs || lhs == 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>
integer nearest(const rational&amp; val, <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0105r1.html#RoundMode">rounding</a> mode = rounding::tie_to_even);
</pre></a>
<blockquote>
<p><i>Returns:</i> the integer nearest in value to <tt>val</tt>.
In the case of a tie (if <tt>val.denom()</tt> would be 2), 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, <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0105r1.html#RoundMode">rounding</a>::all_away_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; stream);

template&lt;class charT, class traits&gt;
  std::basic_ostream&lt;charT,traits&gt;&amp;
    noshowden1(std::basic_ostream&lt;charT,traits&gt;&amp; stream);
</pre>
<blockquote>
These output manipulators control whether a denominator equal to 1 is written.
If <tt>noshowden1</tt> is in effect and the <tt>rational</tt>&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; stream);

template&lt;class charT, class traits&gt;
  std::basic_ostream&lt;charT,traits&gt;&amp;
    nodivalign(std::basic_ostream&lt;charT,traits&gt;&amp; stream);
</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 the solidus <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>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.
The output shall be in lowest terms as if <tt>rhs.normalize()</tt> had been called
just prior to doing the output.
</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>
rational pow(const rational&amp; val, const integer&amp; exp);
</pre>
<blockquote>
<i>Requires:</i> <tt>val != 0 || exp >= 0</tt>.
<p><i>Returns:</i> <tt>rational(1)</tt> if <tt>exp</tt> <tt>==</tt> 0;
otherwise <tt>val</tt> raised to the <tt>exp</tt> power.
<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>
<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>

<pre>
rational modf(const rational&amp; val);
</pre>
<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, stdbill<tt>.</tt>h<sup>@</sup>pobox<tt>.</tt>com.
</body>
</html>
 