mirror of
https://github.com/boostorg/safe_numerics.git
synced 2026-01-23 18:12:09 +00:00
484 lines
14 KiB
XML
484 lines
14 KiB
XML
<?xml version="1.0" encoding="UTF-8"?>
|
|
<!DOCTYPE section PUBLIC "-//Boost//DTD BoostBook XML V1.1//EN"
|
|
"http://www.boost.org/tools/boostbook/dtd/boostbook.dtd">
|
|
<section id="safe_numerics.numeric">
|
|
<title>Numeric<T></title>
|
|
|
|
<?dbhtml stop-chunking?>
|
|
|
|
<section id="safe_numerics.numeric.description">
|
|
<title>Description</title>
|
|
|
|
<para>A type is Numeric if it has the properties of a number.</para>
|
|
|
|
<para>More specifically, a type T is Numeric if there exists a
|
|
specialization of <code>std::numeric_limits<T></code>. See the
|
|
documentation for the standard library class <code>numeric_limits</code>.
|
|
The standard library includes such specializations for all the built-in
|
|
numeric types. Note that this concept is distinct from the C++ standard
|
|
library type traits <code>is_integral</code> and
|
|
<code>is_arithmetic</code>. These latter fulfill the requirement of the
|
|
concept Numeric. But there may types which fulfill the concept of Numeric
|
|
for which <code>std::is_arithmetic<T> == false</code>.</para>
|
|
|
|
<para>There are multiple reasons that we cannot use
|
|
std::is_arithmetic<T> to identify number-like types for our
|
|
purposes:</para>
|
|
|
|
<para><itemizedlist>
|
|
<listitem>
|
|
<para>The main purpose of our concept of Numeric<T> is to
|
|
indicate that the range of type T is available to be queried. Since
|
|
all specializations of Numeric<T> have a member in
|
|
std::numeric_limits<T> we have access to this information when
|
|
needed through the members std::numeric_limits<T>::min() and
|
|
std::numeric_limits<T>::max().</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>There are types which do not fulfill std::arithmetic<T>
|
|
(that is are not built-in numeric types) but still fulfill the
|
|
concept of Numeric<T> (number like "things").</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>The library creates new result types for every expression
|
|
which should also fulfill this concept Numeric. But
|
|
is_arithmetic<T> cannot be specialized for user types.</para>
|
|
</listitem>
|
|
</itemizedlist>So is_arithmetic<T> does not correspond to the same
|
|
set of types as Numeric<T> does.</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title>Notation</title>
|
|
|
|
<informaltable>
|
|
<tgroup cols="2" colsep="1" rowsep="1">
|
|
<colspec align="left"/>
|
|
|
|
<colspec align="left" colwidth="3*"/>
|
|
|
|
<tbody>
|
|
<row>
|
|
<entry><code>T, U, V</code></entry>
|
|
|
|
<entry>A type that is a model of a Numeric type</entry>
|
|
</row>
|
|
|
|
<row>
|
|
<entry><code>t, u</code></entry>
|
|
|
|
<entry>An object of a type modeling a Numeric type</entry>
|
|
</row>
|
|
|
|
<row>
|
|
<entry><code>OS, IS</code></entry>
|
|
|
|
<entry>A type that is a model of an output or input stream</entry>
|
|
</row>
|
|
|
|
<row>
|
|
<entry><code>os, is</code></entry>
|
|
|
|
<entry>An object of a type modeling output or input stream</entry>
|
|
</row>
|
|
</tbody>
|
|
</tgroup>
|
|
</informaltable>
|
|
</section>
|
|
|
|
<section>
|
|
<title>Associated Types</title>
|
|
|
|
<informaltable>
|
|
<tgroup cols="2">
|
|
<colspec align="left"/>
|
|
|
|
<colspec align="left" colwidth="3*"/>
|
|
|
|
<tbody>
|
|
<row>
|
|
<entry><code>std::numeric_limits<T></code></entry>
|
|
|
|
<entry>The numeric_limits class template provides a C++ program
|
|
with information about various properties of the implementation's
|
|
representation of the arithmetic types. See C++ standard
|
|
18.3.2.2.</entry>
|
|
</row>
|
|
</tbody>
|
|
</tgroup>
|
|
</informaltable>
|
|
</section>
|
|
|
|
<section>
|
|
<title>Valid Expressions</title>
|
|
|
|
<para>In addition to the expressions defined in <ulink
|
|
url="http://www.sgi.com/tech/stl/Assignable.html">Assignable</ulink> the
|
|
following expressions must be valid. In the safe_numerics library, a type
|
|
is considered Numeric if and only if it it has an entry in the
|
|
std::numeric_limits table with the following members. Note that this is
|
|
different from the the definition of std::is_arithmetic in that the later
|
|
is required to support all valid expressions which Numeric does not
|
|
require support for all these expressions but only requires that they be
|
|
correctly implemented if they are defined. Also is_arithmetic is only
|
|
defined for built in numeric types while Numeric applies to any user types
|
|
which "look like" a number.<table>
|
|
<title>General</title>
|
|
|
|
<tgroup cols="3">
|
|
<colspec align="left" colwidth="2*"/>
|
|
|
|
<colspec align="left" colwidth="1*"/>
|
|
|
|
<colspec align="left" colwidth="2*"/>
|
|
|
|
<thead>
|
|
<row>
|
|
<entry align="left">Expression</entry>
|
|
|
|
<entry>Return Type</entry>
|
|
|
|
<entry>Return Value</entry>
|
|
</row>
|
|
</thead>
|
|
|
|
<tbody>
|
|
<row>
|
|
<entry><code>Numeric<T></code></entry>
|
|
|
|
<entry><code>true_type</code></entry>
|
|
|
|
<entry/>
|
|
</row>
|
|
|
|
<row>
|
|
<entry><code>Numeric<T>()</code></entry>
|
|
|
|
<entry><code>bool</code></entry>
|
|
|
|
<entry>true</entry>
|
|
</row>
|
|
|
|
<row>
|
|
<entry><code>std::numeric_limits<T>::is_specialized</code></entry>
|
|
|
|
<entry><code>bool</code></entry>
|
|
|
|
<entry><code>true</code></entry>
|
|
</row>
|
|
|
|
<row>
|
|
<entry><code>std::numeric_limits<T>::is_integer</code></entry>
|
|
|
|
<entry><code>bool</code></entry>
|
|
|
|
<entry><code>true</code> or <code>false</code></entry>
|
|
</row>
|
|
|
|
<row>
|
|
<entry><code>std::numeric_limits<T>::is_signed</code></entry>
|
|
|
|
<entry><code>bool</code></entry>
|
|
|
|
<entry><code>true</code> or <code>false</code></entry>
|
|
</row>
|
|
</tbody>
|
|
</tgroup>
|
|
</table></para>
|
|
|
|
<para>Any or all of the following unary operators MAY be defined. Any such
|
|
defined operators shall implement the semantics as described below</para>
|
|
|
|
<table>
|
|
<title>Unary Operators</title>
|
|
|
|
<tgroup cols="3">
|
|
<colspec align="left"/>
|
|
|
|
<colspec align="left"/>
|
|
|
|
<colspec align="left" colwidth="3*"/>
|
|
|
|
<thead>
|
|
<row>
|
|
<entry align="left">Expression</entry>
|
|
|
|
<entry>Return Type</entry>
|
|
|
|
<entry>Semantics</entry>
|
|
</row>
|
|
</thead>
|
|
|
|
<tbody>
|
|
<row>
|
|
<entry><code>-t</code></entry>
|
|
|
|
<entry><code>T</code></entry>
|
|
|
|
<entry>Invert sign</entry>
|
|
</row>
|
|
|
|
<row>
|
|
<entry><code>+t</code></entry>
|
|
|
|
<entry><code>T</code></entry>
|
|
|
|
<entry>unary plus - a no op</entry>
|
|
</row>
|
|
|
|
<row>
|
|
<entry><code>t--</code></entry>
|
|
|
|
<entry><code>T</code></entry>
|
|
|
|
<entry>post decrement</entry>
|
|
</row>
|
|
|
|
<row>
|
|
<entry><code>t++</code></entry>
|
|
|
|
<entry><code>T</code></entry>
|
|
|
|
<entry>post increment</entry>
|
|
</row>
|
|
|
|
<row>
|
|
<entry><code>--t</code></entry>
|
|
|
|
<entry><code>T</code></entry>
|
|
|
|
<entry>pre decrement</entry>
|
|
</row>
|
|
|
|
<row>
|
|
<entry><code>++t</code></entry>
|
|
|
|
<entry><code>T</code></entry>
|
|
|
|
<entry>pre increment</entry>
|
|
</row>
|
|
</tbody>
|
|
</tgroup>
|
|
</table>
|
|
|
|
<para>Any or all of the following binary operators MAY be defined. Any
|
|
defined operators shall implement the semantics as described bellow</para>
|
|
|
|
<table>
|
|
<title>Binary Operators</title>
|
|
|
|
<tgroup cols="3">
|
|
<colspec align="left"/>
|
|
|
|
<colspec align="left"/>
|
|
|
|
<colspec align="left" colwidth="3*"/>
|
|
|
|
<thead>
|
|
<row>
|
|
<entry align="left">Expression</entry>
|
|
|
|
<entry>Return Type</entry>
|
|
|
|
<entry>Semantics</entry>
|
|
</row>
|
|
</thead>
|
|
|
|
<tbody>
|
|
<row>
|
|
<entry><code>t - u</code></entry>
|
|
|
|
<entry><code>V</code></entry>
|
|
|
|
<entry>subtract u from t</entry>
|
|
</row>
|
|
|
|
<row>
|
|
<entry><code>t + u</code></entry>
|
|
|
|
<entry><code>V</code></entry>
|
|
|
|
<entry>add u to t</entry>
|
|
</row>
|
|
|
|
<row>
|
|
<entry><code>t * u</code></entry>
|
|
|
|
<entry><code>V</code></entry>
|
|
|
|
<entry>multiply t by u</entry>
|
|
</row>
|
|
|
|
<row>
|
|
<entry><code>t / u</code></entry>
|
|
|
|
<entry><code>T</code></entry>
|
|
|
|
<entry>divide t by u</entry>
|
|
</row>
|
|
|
|
<row>
|
|
<entry><code>t < u</code></entry>
|
|
|
|
<entry><code>bool</code></entry>
|
|
|
|
<entry><code>true</code> if t less than u, <code>false</code>
|
|
otherwise</entry>
|
|
</row>
|
|
|
|
<row>
|
|
<entry><code>t <= u</code></entry>
|
|
|
|
<entry><code>bool</code></entry>
|
|
|
|
<entry><code>true</code> if t less than or equal to u,
|
|
<code>false</code> otherwise</entry>
|
|
</row>
|
|
|
|
<row>
|
|
<entry><code>t > u</code></entry>
|
|
|
|
<entry><code>bool</code></entry>
|
|
|
|
<entry><code>true</code> if t greater than u, <code>false</code>
|
|
otherwise</entry>
|
|
</row>
|
|
|
|
<row>
|
|
<entry><code>t >= u</code></entry>
|
|
|
|
<entry><code>bool</code></entry>
|
|
|
|
<entry><code>true</code> if t greater than or equal to u,
|
|
<code>false</code> otherwise</entry>
|
|
</row>
|
|
|
|
<row>
|
|
<entry><code>t == u</code></entry>
|
|
|
|
<entry><code>bool</code></entry>
|
|
|
|
<entry><code>true</code> if t equal to u, <code>false</code>
|
|
otherwise</entry>
|
|
</row>
|
|
|
|
<row>
|
|
<entry><code>t != u</code></entry>
|
|
|
|
<entry><code>bool</code></entry>
|
|
|
|
<entry><code>true</code> if t not equal to u, <code>false</code>
|
|
otherwise</entry>
|
|
</row>
|
|
|
|
<row>
|
|
<entry><code>t = u</code></entry>
|
|
|
|
<entry><code><code>T</code></code></entry>
|
|
|
|
<entry>assign value of u to t</entry>
|
|
</row>
|
|
|
|
<row>
|
|
<entry><code>t += u</code></entry>
|
|
|
|
<entry><code><code>T</code></code></entry>
|
|
|
|
<entry>add u to t and assign to t</entry>
|
|
</row>
|
|
|
|
<row>
|
|
<entry><code>t -= u</code></entry>
|
|
|
|
<entry><code><code>T</code></code></entry>
|
|
|
|
<entry>subtract u from t and assign to t</entry>
|
|
</row>
|
|
|
|
<row>
|
|
<entry><code>t *= u</code></entry>
|
|
|
|
<entry><code><code>T</code></code></entry>
|
|
|
|
<entry>multiply t by u and assign to t</entry>
|
|
</row>
|
|
|
|
<row>
|
|
<entry><code>t /= u</code></entry>
|
|
|
|
<entry><code><code>T</code></code></entry>
|
|
|
|
<entry>divide t by u and assign to t</entry>
|
|
</row>
|
|
|
|
<row>
|
|
<entry><code>os << t</code></entry>
|
|
|
|
<entry><code><code>OS &</code></code></entry>
|
|
|
|
<entry>write contents of t to output stream</entry>
|
|
</row>
|
|
|
|
<row>
|
|
<entry><code>is >> t</code></entry>
|
|
|
|
<entry><code><code>IS &</code></code></entry>
|
|
|
|
<entry>read contents of an input stream into t</entry>
|
|
</row>
|
|
</tbody>
|
|
</tgroup>
|
|
</table>
|
|
</section>
|
|
|
|
<section>
|
|
<title>Models</title>
|
|
|
|
<para><code>int, float, safe_signed_integer<int>,
|
|
safe_signed_range<int>, checked_result<int>,
|
|
etc.</code></para>
|
|
</section>
|
|
|
|
<section>
|
|
<title>Header</title>
|
|
|
|
<para><ulink
|
|
url="../../include/boost/safe_numerics/concept/numeric.hpp"><code>#include
|
|
<boost/safe_numerics/concepts/numeric.hpp> </code></ulink></para>
|
|
</section>
|
|
|
|
<section>
|
|
<title>Note on Usage of <code>std::numeric_limits</code></title>
|
|
|
|
<para>This in turn raises another question: Is it "legal" to specialize
|
|
<code>std::numeric_limits</code> for one's own types such as
|
|
<code>safe<int></code>. In my view the standard is ambiguous on
|
|
this. See various interpretations: <itemizedlist>
|
|
<listitem>
|
|
<para><ulink
|
|
url="https://stackoverflow.com/questions/16122912/is-it-ok-to-specialize-stdnumeric-limitst-for-user-defined-number-like-class">is-it-ok-to-specialize-stdnumeric-limitst-for-user-defined-number-like-class</ulink></para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><ulink
|
|
url="https://en.cppreference.com/w/cpp/types/numeric_limits">cppreference.com/w/cpp/types/numeric_limits</ulink></para>
|
|
</listitem>
|
|
</itemizedlist></para>
|
|
|
|
<para>In any case, it seems pretty clear that no harm will come of it. In
|
|
spite of the consideration given to this issue, it turns out that the
|
|
found no real need to implement these predicates. For example, there is no
|
|
"is_numeric<T>" implemented as part of the safe numerics library.
|
|
This may change in the future though. Even if not used, defining and
|
|
maintaining these type requirements in this document has been very
|
|
valuable in keeping the concepts and code more unified and
|
|
understandable.</para>
|
|
|
|
<para>Remember that above considerations apply to other numeric types used
|
|
in this library even though we don't explicitly repeat this information
|
|
for every case.</para>
|
|
</section>
|
|
</section>
|