<html>
<head><title>P2159R1, A Big Decimal</title></head>
<body>

<h2>A Big Decimal Type</h2>

<table border=0>
<tr>
  <td><b>Doc No:</b></td>
  <td>P2159R1</td>
</tr>
<tr>
  <td><b>Date:</b></td>
  <td>2022-12-24</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>LEWG-I, SG6 (Numerics)</td>
</tr>
</table>

<p><hr size=5>
<h2>Contents</h2>

<ul>
<li><a href="#intro">Introduction</a>
<li><a href="#syn">Synopsis</a>
<li><a href="#details">Detailed Descriptions</a>
<ul>
<li><a href="#mem">The <tt>decimal</tt> Class</a>
<ul>
<li><a href="#const">A Member Type and Some Constants</a>
<li><a href="#spec">Special Member Functions and <tt>swap</tt></a>
<li><a href="#ctor">Construction from Other Types</a>
<li><a href="#assgn">Assignment from Other Types</a>
<li><a href="#conv">Conversion to Other Types</a>
<li><a href="#rndsc">Rounding and Scale</a>
<li><a href="#obs">Observers</a>
<li><a href="#mut">Mutators</a>
<li><a href="#comp">Comparisons</a>
<li><a href="#ari">Arithmetic</a>
<li><a href="#siz">Size, etc.</a>
</ul>
<li><a href="#nonmem">Non-member Functions</a>
<ul>
<li><a href="#misc">Miscellaneous Functions</a>
<li><a href="#freeari">Operators</a>
<li><a href="#math"><tt>&lt;cmath&gt;</tt>-like Functions</a>
</ul>
</ul>
</ul>

<p><a name="intro"><hr size=5></a>
<h2>Introduction</h2>
This is a revision of P2159R0 which was discussed in Kona; but the author wasn&rsquo;t
able to attend.&nbsp;&nbsp;The author will be present at the face-to-face meeting in Issaquah.

<p>This paper proposes an exact decimal type that can be used as either a fixed point type or a floating point type
with an implementation-defined maximum precision.&nbsp;&nbsp;An instance will never be a negative zero.

<p>Users can specify at run time a rounding mode and a <i>scale</i>, the number of decimal digits to the right of the decimal point.

<p>Instances would normally act like a floating point type internally, and so addition, subtraction and multiplication
would be exact and so could represent more than the implementation-defined maximum number of digits.&nbsp;&nbsp;Division,
if it would generate a quotient of greater than the maximum precision, will generate a guard digit and then round
to the maximum precision.

<p>Rounding to the user&rsquo;s desired scale occurs when the value becomes externally visible (e.g.,
<nobr><tt>to_integer()</tt>,</nobr> <nobr><tt>to_string()</tt>),</nobr> or when the user explicitly calls one of the member
<nobr><tt>round()</tt></nobr> overloads.&nbsp;&nbsp;Users can turn off rounding (except for division) by explicitly requesting
an out-of-band value for the scale, thus making the object seem to be a floating point value even to the outside world.

<p>Overloads of the few <tt>&lt;cmath&gt;</tt> functions that return exact values are provided as non-member functions.

<p><a name="from1889">This paper assumes that we have, from</a>
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p1889r1.pdf">P1889R1</a>,
the <tt>rounding</tt> enumeration (&sect;3.3) and the unbounded <tt>integer</tt> class (&sect;9.3).

<p><table border=0><tr><td bgcolor=yellow>
<b>Issues:</b>
<ul>
<li>Should all arithmetic operations round to the user&rsquo;s desired scale unless the user has
    explicitly requested a &ldquo;floating&rdquo; scale?
<li>Should the type support NaNs and/or infinities?&nbsp;&nbsp;(This paper assumes support for quiet NaNs and infinities.)
<ul>
<li>Should this depend of whether the C++ implentation&rsquo;s fundamental floating point types have them?
</ul>
</ul>
</td></tr></table>

<p><a name="syn"><hr size=5></a>
<h2>Synopsis</h2>
<pre>
class decimal final
{
public:
  //
  // <a href="#const">A member type and some constants:</a>
  //
    using scale_type = int;
    static constexpr scale_type max_scale = <i><a href="#maxsc">implementation-defined</a></i>;
    static constexpr scale_type floating_scale = INT_MIN;

    static constexpr int max_digits = <i><a href="#maxdigs">implementation-defined</a></i>;

    static constexpr <a href="#from1889">rounding</a> default_rounding = rounding::tie_to_even;
    static constexpr rounding bankers_rounding = rounding::tie_away_zero;

    static constexpr decimal inf = <i>a value that represents positive infinity</i>;
    static constexpr decimal nan = <i>a value that represents a quiet NaN</i>;

  //
  // <a href="#spec">Special member functions and swap:</a>
  //
    explicit decimal(rounding = default_rounding, scale_type = 0);

    decimal(const decimal&amp;);
    decimal(decimal&amp;&amp;);

    decimal&amp; operator=(const decimal&amp;);
    decimal&amp; operator=(decimal&amp;&amp;);

    ~decimal() noexcept;

    void swap(decimal&amp;);

  //
  // <a href="#ctor">Construction from other types:</a>
  //
    template&lt;typename <i>FundamentalArithmeticType</i>&gt;
      decimal(<i>FundamentalArithmeticType</i>, scale_type = <a href="#fundctor"><i>see below</i></a>, rounding = default_rounding);
    explicit decimal(const <a href="#from1889">integer</a>&amp;, scale_type = 0, rounding = default_rounding);
    explicit decimal(const char*, rounding = default_rounding, const char** = nullptr);
    explicit decimal(const std::string&amp;, rounding = default_rounding, std::size_t* = nullptr);

  //
  // <a href="#assgn">Assignment from other types:</a>
  //
    template&lt;typename <i>FundamentalArithmeticType</i>&gt;
      decimal&amp; operator=(<i>FundamentalArithmeticType</i>);
    template&lt;typename <i>FundamentalArithmeticType</i>&gt;
      decimal&amp; assign(<i>FundamentalArithmeticType</i>, scale_type = <a href="#fundasgn"><i>see below</i></a>, rounding = default_rounding);
    decimal&amp; assign(const integer&amp;, scale_type = 0, rounding = default_rounding);
    decimal&amp; assign(const char*, rounding = default_rounding, const char** = nullptr);
    decimal&amp; assign(const std::string&amp;, rounding = default_rounding, std::size_t* = nullptr);

  //
  // <a href="#conv">Conversion to other types:</a>
  //
    explicit operator bool() const noexcept;
    explicit operator long double() const noexcept;

    integer to_integer(rounding = rounding::all_to_zero) const;

    std::string to_string(bool <i>scientific</i> = false) const;</a>
    std::string to_string(int <i>precision</i>, bool <i>scientific</i> = false) const;

  //
  // <a href="#rndsc">Rounding and scale:</a>
  //
    rounding get_rounding() const noexcept;
    void set_rounding(rounding) noexcept;

    scale_type scale() const noexcept;
    scale_type current_scale() const noexcept;
    bool isfloat() const noexcept;

    void set_user_scale(scale_type) noexcept;
    void adjust_scale_by(scale_type) noexcept;
    void change_scale_to(scale_type) noexcept;

  //
  // <a href="#obs">Observers:</a>
  //
    bool iszero() const noexcept;
    bool isneg()  const noexcept;
    bool ispos()  const noexcept;
    bool isnan()  const noexcept;
    bool isinf()  const noexcept;
    bool isinf(bool <i>negative</i>) const noexcept;

    int signum() const;

    decimal rawval() const;

  //
  // <a href="#mut">Mutators:</a>
  //
    void clear() noexcept;
    void all_clear() noexcept;

    decimal&amp; set_to_zero() noexcept;
    decimal&amp; set_to_one(bool <i>negative</i> = false);

    decimal&amp; negate() noexcept;
    decimal&amp; abs() noexcept;

    decimal&amp; round();
    decimal&amp; round(int <i>number_of_digits</i>);
    decimal&amp; round(int <i>number_of_digits</i>, rounding);

  //
  // <a href="#comp">Comparisons:</a>
  //
    std::partial_ordering operator&lt;=&gt;(const decimal&amp;) const;
    bool operator==(const decimal&amp;) const;

  //
  // <a href="#ari">Arithmetic:</a>
  //
    decimal&amp; operator++();
    decimal&amp; operator--();

    decimal  operator++(int);
    decimal  operator--(int);

    decimal&amp; operator+=(const decimal&amp;);
    decimal&amp; operator-=(const decimal&amp;);
    decimal&amp; operator*=(const decimal&amp;);
    decimal&amp; operator/=(const decimal&amp;);

  //
  // <a href="#siz">Size, etc.:</a>
  //
    std::size_t digits();
    std::size_t unnormalized_digits() const noexcept;

    bool empty() const noexcept;
    std::size_t size() const noexcept;
    void shrink_to_fit();
};

//
// <a href="#misc">Miscellaneous non-member functions:</a>
//
using std::swap;
void swap(decimal&amp;, decimal&amp;);

integer to_integer(const decimal&amp;, rounding = rounding::all_to_zero) const;

std::string to_string(const decimal&amp;, bool <i>scientific</i> = false);
std::string to_string(const decimal&amp;, int <i>precision</i>, bool <i>scientific</i> = false);

//
// <a href="#freeari">Non-member operators:</a>
//
decimal operator+(const decimal&amp;);
decimal operator-(const decimal&amp;);

decimal operator+(const decimal&amp;, const decimal&amp;);
decimal operator-(const decimal&amp;, const decimal&amp;);
decimal operator*(const decimal&amp;, const decimal&amp;);
decimal operator/(const decimal&amp;, const decimal&amp;);

//
// <a href="#math"><tt>&lt;cmath&gt;</tt>-like functions:</a>
//
decimal abs(const decimal&amp;) noexcept;
decimal ceil(const decimal&amp;);
decimal floor(const decimal&amp;);
decimal trunc(const decimal&amp;);
decimal round(const decimal&amp;, rounding = rounding::tie_away_zero);
decimal rint(const decimal&amp;);
decimal modf(const decimal&amp;, decimal*);
decimal fmod(const decimal&amp;, const decimal&amp;);
decimal remainder(const decimal&amp;, const decimal&amp;, rounding = rounding::tie_to_even);
decimal sqr(const decimal&amp;);
decimal copysign(const decimal&amp;, const decimal&amp;);
decimal fma(const decimal&amp;, const decimal&amp;, const decimal&amp;);
</pre>

<p><a name="details"><hr size=5></a>
<h2>Detailed descriptions</h2>

<p><a name="mem"><hr size=3></a>
<h3>The <tt>decimal</tt> Class</h3>

<p><a name="const"><hr></a>
<h4>A Member Type and Some Constants</h4>
<pre>
using scale_type = int;
</pre>
<blockquote>
A type alias for the scale type might be useful for documentation or for making code clear about what&rsquo;s being passed
to a function.&nbsp;&nbsp;This should probably be a machine word for efficiency.

<!--<p><table border=0><tr><td bgcolor=lightgrey>
The author <a href="https://www.popularmechanics.com/space/a27259/how-many-particles-are-in-the-entire-universe/">reads</a>
that it&rsquo;s estimated that there are fewer than 10<sup>81</sup> quarks plus electrons in the universe,
so even a 16-bit <tt>int</tt> should suffice.&nbsp;&#x1F60A;
</td></tr></table>-->
</blockquote>

<pre>
<a name="maxsc">static constexpr scale_type max_scale = <i>implementation-defined</i>;</a>
</pre>
<blockquote>
The implementation may limit the values passed to <tt>scale_type</tt> function arguments to &plusmn;<tt>max_scale</tt>.&nbsp;&nbsp;This
should be at least <tt>max_digits</tt> below.
</blockquote>

<pre>
static constexpr scale_type floating_scale = INT_MIN;
</pre>
<blockquote>
The class normally acts like a fixed point type (at least when the value becomes externally visible),
but you can make it act like a floating point type by explicitly setting the desired scale to
<tt>floating_scale</tt>.&nbsp;&nbsp;This just turns off rounding except for division.
</blockquote>

<pre>
<a name="maxdigs">static constexpr int max_digits = <i>implementation-defined</i>;</a>
</pre>
<blockquote>
As a practical matter, we can&rsquo;t have an infinite number of digits; so when using this class
as a fixed point type, exposing the value to the outside world will round the value to
at most <tt>max_digits</tt> digits.&nbsp;&nbsp;This can also happen if the class is being used
as a floating point type when division would generate more than <tt>max_digits</tt> digits,
in which case division will generate a guard digit and then round.

<p>The class should be able to represent at least 38 decimal digits.

<p><table border=0><tr><td bgcolor=lightgrey>
One use for this class could be in a database access library, and the author notes that both
Oracle and SQL Server have exact numeric types that can hold up to 38 decimal digits.&nbsp;&nbsp;That&rsquo;s
where the 38 comes from.&nbsp;&nbsp;(ISO/IEC 9075, the SQL standard, doesn&rsquo;t specify any value
for the precision, and Postgresql allows up to 131072 digits; but that seems over the top.)
</td></tr></table>

<p><table border=0><tr><td bgcolor=lightgrey>
Note that we don&rsquo;t call this a <tt>scale_type</tt> because it&rsquo;s a precision, not a scale.
</td></tr></table>
</blockquote>

<pre>
static constexpr <a href="#from1889">rounding</a> default_rounding = rounding::tie_to_even;
</pre>
<blockquote>
If you don&rsquo;t specify a rounding mode when calling a function that takes a <tt>rounding</tt>
argument, that argument will default to <tt>default_rounding</tt> except as noted.
</blockquote>

<pre>
static constexpr rounding bankers_rounding = rounding::tie_away_zero;
</pre>
<blockquote>
As a convenience for users, there&rsquo;s also a symbol for a rounding mode that might be
more appropriate for financial applications, but this library makes no use of it.
</blockquote>

<pre>
static constexpr decimal inf = <i>a value that represents positive infinity</i>;
static constexpr decimal nan = <i>a value that represents a quiet NaN</i>;
</pre>
<blockquote>
We should probably also have symbols for infinities and NaNs.
<p><table border=0><tr><td bgcolor=yellow>
One likely implementation would have decimal digits stored in a sequence container
with random-access iterators, in which case we might not be able to say <tt>constexpr</tt>
unless the container has a <tt>constexpr</tt> default constructor.&nbsp;&nbsp;That&rsquo;s only
<tt>vector</tt> in <a href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/n4917.pdf">N4917</a>.&nbsp;&nbsp;Should
we allow the implementation to be a <tt>deque</tt>?
</td></tr></table>
</blockquote>

<p><a name="spec"><hr></a>
<h4>Special Member Functions and <tt>swap</tt></h4>
<pre>
explicit decimal(rounding = default_rounding, scale_type = 0);
</pre>
<blockquote>
The default constructor constructs a <tt>decimal</tt> equal to zero;
and it can optionally be used to initialize the rounding mode and the user&rsquo;s requested scale.
</blockquote>

<pre>
decimal(const decimal&amp;);
decimal& operator=(const decimal&amp;);

decimal(decimal&amp;&amp;);
decimal& operator=(decimal&amp;&amp;);

~decimal() noexcept;

void swap(decimal&amp;);
</pre>
<blockquote>
<tt>decimal</tt>s are freely copyable, moveable, and swappable.
</blockquote>

<p><a name="ctor"><hr></a>
<h4>Construction from Other Types</h4>
<pre>
<a name="fundctor">template&lt;typename <i>FundamentalArithmeticType</i>&gt;</a>
  decimal(<i>FundamentalArithmeticType</i>, scale_type = <i>?</i>, rounding = default_rounding);
</pre>
<blockquote>
An implementation would probably provide three constructor templates for
implicit conversion from fundamental arithmetic types, one for signed integers,
one for unsigned integers, and one for floating point values.&nbsp;&nbsp;If
the only argument is an integer, the scale defaults to zero, otherwise it defaults
to <tt>floating_scale</tt>.
</blockquote>

<pre>
explicit decimal(const <a href="#from1889">integer</a>&, scale_type = 0, rounding = default_rounding);
</pre>
<blockquote>
There&rsquo;s no implicit conversion from <tt>integer</tt>s because both <tt>decimal</tt> and <tt>integer</tt>
have implicit conversions from fundamental arithmetic types which could lead to ambiguity.
</blockquote>

<pre>
<a name="strctor">explicit decimal(const char*        <i>value</i>, rounding = default_rounding, const char** <i>termptr</i> = nullptr);</a>
explicit decimal(const std::string&amp; <i>value</i>, rounding = default_rounding, std::size_t* <i>termpos</i> = nullptr);
</pre>
<blockquote>
Instances can also be explicitly constructed</a> from C-style strings and <tt>std::string</tt>s.&nbsp;&nbsp;When
constructing from strings, the scale is inferred from the position of the decimal point (or its absence).&nbsp;&nbsp;The
string may begin with a <tt>'+'</tt> or a <tt>'-'</tt>, and it may be in either fixed-point or scientific notation.&nbsp;&nbsp;The
<tt>'e'</tt> in scientific notation may be upper or lower case.

<p>An optional third argument can be used to discover the character that terminated the parse:
<ul>
<li>If <tt><i>termptr</i></tt> is not <tt>nullptr</tt>, <tt>*<i>termptr</i></tt> will be set to a pointer to the character
    that terminated the parse, which will be a pointer to a <tt>'\0'</tt> if the parse continued to the end of the string.
<li>If <tt><i>termpos</i></tt> is not <tt>nullptr</tt>, <tt>*<i>termpos</i></tt> will be set to the position of the character
    that terminated the parse, which will be <nobr><tt><i>value</i>.size()</tt></nobr> if the parse continued to the end of the string.
</ul>

<p><table border=0><tr><td bgcolor=yellow>
<b>Issue:</b>&nbsp;&nbsp;should construction from strings be templates?&nbsp;&nbsp;We expect that we&rsquo;ll be dealing with
only <tt>'+'</tt>, <tt>'-'</tt>, <tt>'.'</tt>, <tt>'E'</tt>, <tt>'e'</tt> and decimal digits, but the number could be part of
a larger string in some language other than English.&nbsp;&nbsp;Also, should we allow non-Arabic (e.g., Devanagari) digits?&nbsp;&nbsp;This
issue also applies to assignment from strings below.
</td></tr></table>
</blockquote>

<p><a name="assgn"><hr></a>
<h4>Assignment from Other Types</h4>
<pre>
template&lt;typename <i>FundamentalArithmeticType</i>&gt;
  decimal&amp; operator=(<i>FundamentalArithmeticType</i>);
</pre>
<blockquote>
Instances can be assigned values of any fundamental arithmetic type.&nbsp;&nbsp;The
desired scale and rounding mode will default as do the implicit constructors.
</blockquote>

<pre>
<a name="fundasgn">template&lt;typename <i>FundamentalArithmeticType</i>&gt;</a>
  decimal&amp; assign(<i>FundamentalArithmeticType</i>, scale_type = <i>?</i>, rounding = default_rounding);
</pre>
<blockquote>
There&rsquo;s also an <tt>assign</tt> member template that allows you to specify a scale and a rounding
mode.&nbsp;&nbsp;As with the implicit constructors, if the only argument is an integer,
the scale will default to zero; but if it&rsquo;s a floating point value, the scale will default to
<tt>floating_scale</tt>.
</blockquote>

<pre>
decimal& assign(const integer&, scale_type = 0, rounding = default_rounding);
</pre>
<blockquote>
You can also explicitly assign <tt>integer</tt>s and optionally specify a scale and rounding
mode.&nbsp;&nbsp;There&rsquo;s no <nobr><tt>operator=(integer)</tt></nobr> because both <tt>decimal</tt>
and <tt>integer</tt> have implicit conversions from fundamental arithmetic types which could lead to ambiguity.
</blockquote>

<pre>
decimal&amp; assign(const char*, rounding = default_rounding, const char** = nullptr);
decimal&amp; assign(const std::string&amp;, rounding = default_rounding, std::size_t* = nullptr);
</pre>
<blockquote>
Assignment from strings behaves like <a href="#strctor">construction from strings</a>.
</blockquote>

<p><a name="conv"><hr></a>
<h4>Conversion to Other Types</h4>
<pre>
explicit operator bool() const noexcept;
</pre>
<blockquote>
The conversion to <tt>bool</tt> returns whether <tt>*this</tt> is non-zero.&nbsp;&nbsp;It&rsquo;s
intended to support the <nobr>&ldquo;<tt>if(<i>my_decimal</i>)</tt>&rdquo;</nobr> idiom.&nbsp;&nbsp;It
returns <tt>false</tt> if <tt>*this</tt> is a NaN.
</blockquote>

<pre>
explicit operator long double() const noexcept;
</pre>
<blockquote>
Conversion to <tt>long</tt> <tt>double</tt> is also provided.&nbsp;&nbsp;If <tt>*this</tt> is finite
but outside the range, [<tt>LDBL_MIN</tt>,<tt>LDBL_MAX</tt>], the function will return <tt>HUGE_VALL</tt>
with <tt>errno</tt> set to <tt>ERANGE</tt>.&nbsp;&nbsp;Conversion to <tt>long</tt>&nbsp;<tt>double</tt>
can quietly result in loss of precision.

<p><table border=0>
<tr><td bgcolor=yellow>
<b>Issue:</b>&nbsp;&nbsp;should we throw an exception on overflow instead of returning <tt>HUGE_VALL</tt>?&nbsp;&nbsp;Or
maybe return infinity even if <tt>*this</tt> is finite but too big?
</td></tr><tr><td bgcolor=yellow>
<b>Issue:</b>&nbsp;&nbsp;should we have explicit conversions to <i>all</i> the fundamental arithmetic types?&nbsp;&nbsp;This
could allow finer detection of overflow if we throw exceptions.
</td></tr><tr><td bgcolor=yellow>
<b>Issue:</b>&nbsp;&nbsp;what behavior should be specified if the <tt>decimal</tt> class supports
NaNs and/or infinities but the C++ implementation&rsquo;s <tt>long</tt> <tt>double</tt> doesn&rsquo;t?
</td></tr></table>
</blockquote>

<pre>
integer to_integer(rounding = rounding::all_to_zero) const;
</pre>
<blockquote>
The <tt>to_integer</tt> function makes a copy of <tt>*this</tt> and then rounds the copy.&nbsp;&nbsp;By
default, the value will be truncated toward zero; but you can specify a different rounding mode if you
need to.&nbsp;&nbsp;This function will throw an exception if <tt>*this</tt> is a NaN or an infinity.
</blockquote>

<pre>
<a name="tostring">std::string to_string(bool <i>scientific</i> = false) const;</a>
std::string to_string(int <i>precision</i>, bool <i>scientific</i> = false) const;</a>
</pre>
<blockquote>
The <tt>to_string()</tt> function makes a copy of <tt>*this</tt>, rounds the copy,
and then returns that value in either fixed-point or scientific notation.&nbsp;&nbsp;A
decimal point will be a period.&nbsp;&nbsp;The string can begin
with <tt>'-'</tt>, but it will never begin with <tt>'+'</tt>.

<p>If <tt><i>precision</i></tt> is not passed, it will default to a number of digits appropriate
given the user&rsquo;s requested scale; otherwise, the function rounds to <tt><i>precision</i></tt>
decimal digits, or to <a href="#maxdigs"><tt>max_digits</tt></a> digits if <tt></i>precision</i></tt>
is greater than <tt>max_digits</tt>.&nbsp;&nbsp;If <tt><i>precision</i></tt> is exactly <tt>INT_MIN</tt>,
no rounding will occur.

<p>In fixed-point notation (<tt><i>scientific</i></tt>&nbsp;<tt>==</tt>&nbsp;<tt>false</tt>):
<ul>
<li>If the value is an integer, there will be no decimal point.
<li>If the absolute value is less than one, the string (after a possible <tt>'-'</tt>)
    will begin with <tt>"0."</tt>; and there could be insignificant zeros
    after the decimal point.
<li>If the absolute value requires more digits than are currently stored,
    there could be trailing zeros.
</ul>

<p>In scientific notation (<tt><i>scientific</i></tt>&nbsp;<tt>==</tt>&nbsp;<tt>true</tt>):
<ul>
<li>If only one digit is produced, there will be no decimal point.
<li>The <tt>'e'</tt> will always be lower case.
<li>The exponent will be returned as at least two digits, possibly with a leading zero.
</ul>

<!--<p>If the value contains too few digits to write an integer (for example, because trailing zeros
have been discarded), the value will be returned in scientific notation regardless of
the <tt><i>sci</i></tt> argument.-->

<p><table border=0><tr><td bgcolor=lightgrey>
The <tt><i>scientific</i></tt> and <tt><i>precision</i></tt> arguments are intended mainly to generate
strings that are suitable for the output stream <tt><b>&lt;&lt;</b></tt> operator, but
there&rsquo;s no compelling reason to keep them secret and disallow their use for other purposes.
</td></tr></table>
</blockquote>

<p><a name="rndsc"><hr></a>
<h4>Rounding and Scale</h4>
<pre>
rounding get_rounding() const noexcept;
void set_rounding(rounding = default_rounding) noexcept;
</pre>
<blockquote>
The user&rsquo;s requested rounding mode can be examined and changed after construction.
</blockquote>

<pre>
<a name="scale">int scale() const noexcept;</a>
int current_scale() const noexcept;
bool isfloat() const noexcept { /*<i>as if</i>*/ return scale() == floating_scale; }
</pre>
<blockquote>
<tt>scale()</tt> returns the user&rsquo;s desired scale; <tt>current_scale()</tt>
returns the scale of the current representation before rounding.
</blockquote>

<pre>
void set_user_scale(scale_type) noexcept;
void adjust_scale_by(scale_type) noexcept;
void change_scale_to(scale_type) noexcept;
</pre>
<blockquote>
<p><tt>set_user_scale(scale_type)</tt> allows the user to set the desired scale after construction
without changing the represented value.

<p><tt>adjust_scale_by(scale_type <i>adj</i>)</tt> adds <tt><i>adj</i></tt> to the
current internal scale without changing the raw (unscaled) value.&nbsp;&nbsp;This
has the effect of multiplying the represented value by
<nobr>10<sup><tt>&minus;<i>adj</i></tt></tt></sup>.</nobr>

<p><tt>change_scale_to(scale_type <i>new_scale</i>)</tt> just sets the current internal scale.&nbsp;&nbsp;This
has the effect of arbitrarily setting the represented value to 
<nobr><a href="#rawval"><tt>rawval()</tt></a>&nbsp;&times;&nbsp;10<sup><tt>&minus;<i>new_scale</i></tt></sup>.</nobr>
</blockquote>

<p>All thesee functions run in constant time.

<p><a name="obs"><hr></a>
<h4>Observers</h4>
<pre>
bool iszero() const noexcept;
bool isneg()  const noexcept;
bool ispos()  const noexcept;
bool isnan()  const noexcept;
bool isinf()  const noexcept;
bool isinf(bool <i>negative</i>) const noexcept;
</pre>
<blockquote>
All except <tt>isnan()</tt> return <tt>false</tt> if <tt>*this</tt> is a NaN.&nbsp;&nbsp;All run in constant time.
</blockquote>

<pre>
int signum() const;
</pre>
<blockquote>
<tt>signum()</tt> returns +1 if <tt>*this</tt> is greater than zero, 0 if <tt>*this</tt> is equal to zero,
or &minus;1 if <tt>*this</tt> is less than zero.&nbsp;&nbsp;It throws an exception if <tt>*this</tt>
is a NaN, otherwise it runs in constant time.
</blockquote>

<pre>
<a name="rawval">decimal rawval() const;</a>
</pre>
<blockquote>
<tt>rawval()</tt> just returns a copy of <tt>*this</tt> with the current scale set to zero,
the effect being to return an integer value made of the currently represented
digits.&nbsp;&nbsp;It doesn&rsquo;t change the user&rsquo;s requested scale.
</blockquote>

<p><a name="mut"><hr></a>
<h4>Mutators</h4>
<pre>
void clear() noexcept;
void all_clear() noexcept;
decimal&amp; set_to_zero() noexcept;
</pre>
<blockquote>
<tt>clear()</tt> and <tt>set_to_zero()</tt> both assign zero to <tt>*this</tt> without changing
the user&rsquo;s requested scale or rounding mode.&nbsp;&nbsp;<nobr><tt>all_clear()</tt></nobr>
has the additional effect of setting the requested scale to zero and the rounding mode to <tt>default_rounding</tt>.
</blockquote>

<pre>
decimal&amp; set_to_one(bool <i>negative</i> = false);
</pre>
<blockquote>
<p><tt>set_to_one(false)</tt> assigns +1 to <tt>*this</tt>;
<tt>set_to_one(true)</tt> assigns &minus;1 to <tt>*this</tt>.
</blockquote>

<pre>
decimal&amp; negate() noexcept;
</pre>
<blockquote>
<tt>negate()</tt> changes the sign of <tt>*this</tt> if <tt>*this</tt> is non-zero and not a NaN.&nbsp;&nbsp;It
will never create a negative zero (or a negative NaN, whatever that could mean).&nbsp;&nbsp;It runs in constant time.
</blockquote>

<pre>
decimal&amp; abs() noexcept;
</pre>
<blockquote>
<tt>abs()</tt> unconditionally makes <tt>*this</tt> non-negative.&nbsp;&nbsp;It runs in constant time.
</blockquote>

<pre>
<a name="norm">decimal&amp; round();</a>
decimal&amp; round(int <i>number_of_digits</i>);
decimal&amp; round(int <i>number_of_digits</i>, rounding);
</pre>
<blockquote>
The <tt>round()</tt> function with no argument does nothing if the user requested <a href="#const"><tt>floating_scale</tt></a>,
otherwise it rounds to a number of digits appropriate given the user&rsquo;s requested scale using the user&rsquo;s requested rounding mode.

<p>The other overloads round to a particular number of decimal digits without regard to the user&rsquo;s
requested scale (and so round even if the user requested <tt>floating_scale</tt>).&nbsp;&nbsp;If
no rounding mode is specified, it defaults to the user&rsquo;s requested mode.&nbsp;&nbsp;If <tt><i>number_of_digits</i></tt>
is less than one, <tt>*this</tt> is set to zero.
</blockquote>

All but <tt>clear()</tt> and <tt>all_clear()</tt> return <tt>*this</tt>.

<p><a name="comp"><hr></a>
<h4>Comparisons</h4>
<pre>
std::partial_ordering operator&lt;=&gt;(const decimal&amp;) const;
bool operator==(const decimal&amp;) const;
</pre>

<p><table border=0><tr><td bgcolor=yellow>
If it&rsquo;s decided that <tt>decimal</tt>s needn&rsquo;t support NaNs,
then the spaceship operator could return <tt>strong_ordering</tt>.
</td></tr></table>

<p><a name="ari"><hr></a>
<h4>Arithmetic</h4>
<pre>
decimal&amp; operator++();
decimal&amp; operator--();

decimal  operator++(int);
decimal  operator--(int);
</pre>
<blockquote>
The increment and decrement operators add or subtract 1.0 as expected; they don&rsquo;t just
add &plusmn;1 to the currently represented LSD.
</blockquote>

<pre>
decimal&amp; operator+=(const decimal&amp;);
decimal&amp; operator-=(const decimal&amp;);
decimal&amp; operator*=(const decimal&amp;);
decimal&amp; operator/=(const decimal&amp;);
</pre>
<blockquote>
Any operation for which either operand is a NaN yields a NaN; otherwise addition, subtraction
and multiplication are exact and so can generate more than <a href="#maxdigs"><tt>max_digits</tt></a>
digits.&nbsp;&nbsp;Division, if it would generate a quotient of more than <tt>max_digits</tt> digits,
generates a guard digit and then rounds using the user&rsquo;s requested rounding mode.

<p>Zero divided by zero and infinity minus ínfinity yield a NaN; other division by zero yields &plusmn;infinity.
</blockquote>

<p><a name="siz"><hr></a>
<h4>Size, etc.</h4>
<pre>
std::size_t digits();
std::size_t unnormalized_digits() const noexcept;
</pre>
<blockquote>
<tt>unnormalized_digts()</tt> returns the number of decimal digits currently represented (before rounding).

<p><tt>digits()</tt> first calls <nobr><tt>this-&gt;round()</tt></nobr>
and then returns the number of digits represented.&nbsp;&nbsp;This could be fewer
than the number of significant digits if trailing zeros to the right of the decimal point
are not stored.
</blockquote>
<pre>
bool empty() const noexcept;
std::size_t size() const noexcept;
void shrink_to_fit();
</pre>
<blockquote>
The internal representation of the value is probably stored in a standard container of some sort;
and <nobr><tt>empty()</tt></nobr>, <nobr><tt>size()</tt></nobr> and <nobr><tt>shrink_to_fit()</tt></nobr>
all just call that container&rsquo;s functions of the same name.
</blockquote>

<p><a name="nonmem"><hr size=3></a>
<h3>Non-member Functions</h3>

<p><a name="misc"><hr></a>
<h4>Miscellaneous Functions</h4>

<pre>
using std::swap;
void swap(decimal&amp;, decimal&amp;);

integer to_integer(const decimal&amp;, rounding = rounding::all_to_zero) const;

std::string to_string(const decimal&amp;, bool <i>scientific</i> = false);
std::string to_string(const decimal&amp;, int <i>precision</i>, bool <i>scientific</i> = false);
</pre>

All have the same semantics as do their corresponding member functions.

<p><a name="freeari"><hr></a>
<h4>Operators</h4>
<pre>
decimal operator+(const decimal&amp;);
decimal operator-(const decimal&amp;);
</pre>
<blockquote>
The unary <tt><b>+</b></tt> operator returns a copy of its argument;
the unary <tt><b>-</b></tt> operator returns a negated copy of its argument.
</blockquote>
<pre>
decimal operator+(const decimal&amp; <i>lhs</i>, const decimal&amp; <i>rhs</i>);
decimal operator-(const decimal&amp; <i>lhs</i>, const decimal&amp; <i>rhs</i>);
decimal operator*(const decimal&amp; <i>lhs</i>, const decimal&amp; <i>rhs</i>);
decimal operator/(const decimal&amp; <i>lhs</i>, const decimal&amp; <i>rhs</i>);
</pre>
<blockquote>
Any operation for which either operand is a NaN yields a NaN; otherwise addition, subtraction
and multiplication are exact and so can generate more than <a href="#maxdigs"><tt>max_digits</tt></a>
digits.&nbsp;&nbsp;Division, if it would generate a quotient of more than <tt>max_digits</tt> digits,
generates a guard digit and then rounds using the user&rsquo;s requested rounding mode.

<p>Zero divided by zero and infinity minus ínfinity yield a NaN; other division by zero yields &plusmn;infinity.

<p>The result will have <tt><i>lhs</i></tt>&rsquo;s desired scale and rounding mode.&nbsp;&nbsp;Note
that this implies that addition and multiplication are not commutative in the strictest sense of that term,
although they will be commutative as far as the value of the sum or product is concerned.
</blockquote>

<p><a name="math"><hr></a>
<h4><tt>&lt;cmath&gt;</tt>-like Functions</h4>
<pre>
decimal abs(const decimal&amp;) noexcept;</a>
decimal ceil(const decimal&amp;);</a>
decimal floor(const decimal&amp;);
decimal trunc(const decimal&amp;);
decimal round(const decimal&amp;, rounding = rounding::tie_away_zero);
decimal rint(const decimal&amp;);
decimal modf(const decimal&amp;, decimal*);
decimal fmod(const decimal&amp;, const decimal&amp;);
decimal remainder(const decimal&amp;, const decimal&amp;, rounding = rounding::tie_to_even);
decimal sqr(const decimal&amp;);
decimal copysign(const decimal&amp;, const decimal&amp;);
decimal fma(const decimal&amp;, const decimal&amp;, const decimal&amp;);
</pre>

A few <tt>&lt;cmath&gt;</tt>-like functions that are expected to return exact values
are supplied.&nbsp;&nbsp;All have behavior that mimics the standard functions of the same name.

<p><a name="nonmemrnd">Note that the non-member <tt>round</tt> function</a>
allows you to specify a rounding mode.&nbsp;&nbsp;This
defaults to <tt>tie_away_zero</tt> which mimics <nobr><tt>std::round()</tt>.</nobr>

<!--
<p>Since calling any of the <tt>ceil</tt>, <tt>floor</tt>, <tt>trunc</tt>,
<tt>round</tt> or <tt>rint</tt> functions explicitly requests an integer value,
the returned value&rsquo;s <a href="#scale"><nobr><tt>scale()</tt></nobr></a>
will always return 0, and <a href="#scale"><nobr><tt>current_scale()</tt></nobr></a>
could return a value less than zero if trailing zeros have been rounded away
(because there are fewer than zero digts to the <i>right</i> of the decimal point).
-->

<p>The <tt>remainder</tt> function also allows specifying a rounding mode
for the quotient of the first two arguments.&nbsp;&nbsp;This
defaults to <tt>tie_to_even</tt> which yields the IEEE&nbsp;754 remainder (like
<nobr><tt>std::remainder()</tt></nobr> does);
but users can compute other kinds of remainders if they want to.

<p><table border=0><tr><td bgcolor=yellow>
<b>Issue:</b>&nbsp;&nbsp;should we also require <tt>sqrt()</tt> even though it
likely wouldn&rsquo;t return an exact value?&nbsp;&nbsp;If so, should it take
an optional <tt>rounding</tt> argument?
</td></tr></table>

<p>The <tt>fma</tt> function doesn&rsquo;t do anything special since no rounding would occur
between the multiplication and the addition in any event; but the function is included
because it&rsquo;s &ldquo;canonical&rdquo;, and because it might simplify updating legacy code
to use <tt>decimal</tt>s.&nbsp;&nbsp;The <tt>FP_FAST_FMA</tt> macro tells you nothing about this function.

<p>For all of these functions, the result&rsquo;s requested scale and rounding mode
will be the same as those of the first, or only, argument.

<p><hr size=5>
</body>
</html>
