multiprecision/doc/html/boost_multiprecision/intro.html
2019-10-17 16:29:54 +01:00

788 lines
48 KiB
HTML

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
<title>Introduction</title>
<link rel="stylesheet" href="../multiprecision.css" type="text/css">
<meta name="generator" content="DocBook XSL Stylesheets V1.79.1">
<link rel="home" href="../index.html" title="Chapter&#160;1.&#160;Boost.Multiprecision">
<link rel="up" href="../index.html" title="Chapter&#160;1.&#160;Boost.Multiprecision">
<link rel="prev" href="../index.html" title="Chapter&#160;1.&#160;Boost.Multiprecision">
<link rel="next" href="tut.html" title="Tutorial">
</head>
<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
<table cellpadding="2" width="100%"><tr>
<td valign="top"><img alt="Boost C++ Libraries" width="277" height="86" src="../../../../../boost.png"></td>
<td align="center"><a href="../../../../../index.html">Home</a></td>
<td align="center"><a href="../../../../../libs/libraries.htm">Libraries</a></td>
<td align="center"><a href="http://www.boost.org/users/people.html">People</a></td>
<td align="center"><a href="http://www.boost.org/users/faq.html">FAQ</a></td>
<td align="center"><a href="../../../../../more/index.htm">More</a></td>
</tr></table>
<hr>
<div class="spirit-nav">
<a accesskey="p" href="../index.html"><img src="../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../index.html"><img src="../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="tut.html"><img src="../../../../../doc/src/images/next.png" alt="Next"></a>
</div>
<div class="section">
<div class="titlepage"><div><div><h2 class="title" style="clear: both">
<a name="boost_multiprecision.intro"></a><a class="link" href="intro.html" title="Introduction">Introduction</a>
</h2></div></div></div>
<p>
The Multiprecision Library provides <a class="link" href="tut/ints.html" title="Integer Types">integer</a>,
<a class="link" href="tut/rational.html" title="Rational Number Types">rational</a>, <a class="link" href="tut/floats.html" title="floating-point Numbers">floating-point</a>,
and <a class="link" href="tut/complex.html" title="Complex Number Types">complex</a> types in
C++ that have more range and precision than C++'s ordinary built-in types.
The big number types in Multiprecision can be used with a wide selection of
basic mathematical operations, elementary transcendental functions as well
as the functions in Boost.Math. The Multiprecision types can also interoperate
with any <a href="https://en.cppreference.com/w/cpp/language/types" target="_top">fundamental
(built-in) type</a> in C++ using clearly defined conversion rules. This
allows Boost.Multiprecision to be used for all kinds of mathematical calculations
involving integer, rational and floating-point types requiring extended range
and precision.
</p>
<p>
Multiprecision consists of a generic interface to the mathematics of large
numbers as well as a selection of big number back-ends, with support for integer,
rational, floating-point, and complex types. Boost.Multiprecision provides
a selection of back-ends provided off-the-rack in including interfaces to GMP,
MPFR, MPIR, MPC, TomMath as well as its own collection of Boost-licensed, header-only
back-ends for integers, rationals and floats. In addition, user-defined back-ends
can be created and used with the interface of Multiprecision, provided the
class implementation adheres to the necessary <a class="link" href="ref/backendconc.html" title="Backend Requirements">concepts</a>.
</p>
<p>
Depending upon the number type, precision may be arbitrarily large (limited
only by available memory), fixed at compile time (for example, 50 or 100 decimal
digits), or a variable controlled at run-time by member functions. The types
are <a href="https://en.wikipedia.org/wiki/Expression_templates" target="_top">expression
templates</a> - enabled for better performance than naive user-defined
types.
</p>
<p>
The Multiprecision library comes in two distinct parts:
</p>
<div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; ">
<li class="listitem">
An expression-template-enabled front-end <code class="computeroutput"><span class="identifier">number</span></code>
that handles all the operator overloading, expression evaluation optimization,
and code reduction.
</li>
<li class="listitem">
A selection of back-ends that implement the actual arithmetic operations,
and need conform only to the reduced interface requirements of the front-end.
</li>
</ul></div>
<p>
Separation of front-end and back-end allows use of highly refined, but restricted
license libraries where possible, but provides Boost license alternatives for
users who must have a portable unconstrained license. Which is to say some
back-ends rely on 3rd party libraries, but a header-only Boost license version
is always available (if somewhat slower).
</p>
<h6>
<a name="boost_multiprecision.intro.h0"></a>
<span class="phrase"><a name="boost_multiprecision.intro.getting_started"></a></span><a class="link" href="intro.html#boost_multiprecision.intro.getting_started">Getting
started with Boost.Multiprecision</a>
</h6>
<p>
Should you just wish to 'cut to the chase' just to get bigger integers and/or
bigger and more precise reals as simply and portably as possible, close to
'drop-in' replacements for the <a href="https://en.cppreference.com/w/cpp/language/types" target="_top">fundamental
(built-in) type</a> analogs, then use a fully Boost-licensed number type,
and skip to one of more of :
</p>
<div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; ">
<li class="listitem">
<a class="link" href="tut/ints/cpp_int.html" title="cpp_int">cpp_int</a> for
multiprecision integers,
</li>
<li class="listitem">
<a class="link" href="tut/rational/cpp_rational.html" title="cpp_rational">cpp_rational</a>
for rational types,
</li>
<li class="listitem">
<a class="link" href="tut/floats/cpp_bin_float.html" title="cpp_bin_float">cpp_bin_float</a>
and <a class="link" href="tut/floats/cpp_dec_float.html" title="cpp_dec_float">cpp_dec_float</a>
for multiprecision floating-point types,
</li>
<li class="listitem">
<a class="link" href="tut/complex/cpp_complex.html" title="cpp_complex">cpp_complex</a>
for complex types.
</li>
</ul></div>
<p>
The library is very often used via one of the predefined convenience <code class="computeroutput"><span class="keyword">typedef</span></code>s like <code class="computeroutput"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">multiprecision</span><span class="special">::</span><span class="identifier">int128_t</span></code>
or <code class="computeroutput"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">multiprecision</span><span class="special">::</span><span class="identifier">cpp_bin_float_quad</span></code>.
</p>
<p>
For example, if you want a signed, 128-bit fixed size integer:
</p>
<pre class="programlisting"><span class="preprocessor">#include</span> <span class="special">&lt;</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">multiprecision</span><span class="special">/</span><span class="identifier">cpp_int</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">&gt;</span> <span class="comment">// Integer types.</span>
<span class="identifier">boost</span><span class="special">::</span><span class="identifier">multiprecision</span><span class="special">::</span><span class="identifier">int128_t</span> <span class="identifier">my_128_bit_int</span><span class="special">;</span>
</pre>
<p>
Alternatively, and more adventurously, if you wanted an <a href="http://en.wikipedia.org/wiki/Arbitrary-precision_arithmetic" target="_top">arbitrary
precision</a> integer type using <a href="http://gmplib.org" target="_top">GMP</a>
as the underlying implementation then you could use:
</p>
<pre class="programlisting"><span class="preprocessor">#include</span> <span class="special">&lt;</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">multiprecision</span><span class="special">/</span><span class="identifier">gmp</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">&gt;</span> <span class="comment">// Defines the wrappers around the GMP library's types</span>
<span class="identifier">boost</span><span class="special">::</span><span class="identifier">multiprecision</span><span class="special">::</span><span class="identifier">mpz_int</span> <span class="identifier">myint</span><span class="special">;</span> <span class="comment">// Arbitrary precision integer type.</span>
</pre>
<p>
Or for a simple, portable 128-bit floating-point close to a drop-in for a
<a href="https://en.cppreference.com/w/cpp/language/types" target="_top">fundamental (built-in)
type</a> like <code class="computeroutput"><span class="keyword">double</span></code>, usually
64-bit
</p>
<pre class="programlisting"><span class="preprocessor">#include</span> <span class="special">&lt;</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">multiprecision</span><span class="special">/</span><span class="identifier">cpp_bin_float</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">&gt;</span>
<span class="identifier">boost</span><span class="special">::</span><span class="identifier">multiprecision</span><span class="special">::</span><span class="identifier">cpp_bin_float_quad</span> <span class="identifier">my_quad_real</span><span class="special">;</span>
</pre>
<p>
Alternatively, you can compose your own 'custom' multiprecision type, by combining
<code class="computeroutput"><span class="identifier">number</span></code> with one of the predefined
back-end types. For example, suppose you wanted a 300 decimal digit floating-point
type based on the <a href="http://www.mpfr.org" target="_top">MPFR</a> library. In
this case, there's no predefined <code class="computeroutput"><span class="keyword">typedef</span></code>
with that level of precision, so instead we compose our own:
</p>
<pre class="programlisting"><span class="preprocessor">#include</span> <span class="special">&lt;</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">multiprecision</span><span class="special">/</span><span class="identifier">mpfr</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">&gt;</span> <span class="comment">// Defines the Backend type that wraps MPFR.</span>
<span class="keyword">namespace</span> <span class="identifier">mp</span> <span class="special">=</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">multiprecision</span><span class="special">;</span> <span class="comment">// Reduce the typing a bit later...</span>
<span class="keyword">typedef</span> <span class="identifier">mp</span><span class="special">::</span><span class="identifier">number</span><span class="special">&lt;</span><span class="identifier">mp</span><span class="special">::</span><span class="identifier">mpfr_float_backend</span><span class="special">&lt;</span><span class="number">300</span><span class="special">&gt;</span> <span class="special">&gt;</span> <span class="identifier">my_float</span><span class="special">;</span>
<span class="identifier">my_float</span> <span class="identifier">a</span><span class="special">,</span> <span class="identifier">b</span><span class="special">,</span> <span class="identifier">c</span><span class="special">;</span> <span class="comment">// These variables have 300 decimal digits precision.</span>
</pre>
<p>
We can repeat the above example, but with the expression templates disabled
(for faster compile times, but slower runtimes) by passing a second template
argument to <code class="computeroutput"><span class="identifier">number</span></code>:
</p>
<pre class="programlisting"><span class="preprocessor">#include</span> <span class="special">&lt;</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">multiprecision</span><span class="special">/</span><span class="identifier">mpfr</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">&gt;</span> <span class="comment">// Defines the Backend type that wraps MPFR.</span>
<span class="keyword">namespace</span> <span class="identifier">mp</span> <span class="special">=</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">multiprecision</span><span class="special">;</span> <span class="comment">// Reduce the typing a bit later...</span>
<span class="keyword">typedef</span> <span class="identifier">mp</span><span class="special">::</span><span class="identifier">number</span><span class="special">&lt;</span><span class="identifier">mp</span><span class="special">::</span><span class="identifier">mpfr_float_backend</span><span class="special">&lt;</span><span class="number">300</span><span class="special">&gt;,</span> <span class="identifier">et_off</span><span class="special">&gt;</span> <span class="identifier">my_float</span><span class="special">;</span>
<span class="identifier">my_float</span> <span class="identifier">a</span><span class="special">,</span> <span class="identifier">b</span><span class="special">,</span> <span class="identifier">c</span><span class="special">;</span> <span class="comment">// These variables have 300 decimal digits precision</span>
</pre>
<p>
We can also mix arithmetic operations between different types, provided there
is an unambiguous implicit conversion from one type to the other:
</p>
<pre class="programlisting"><span class="preprocessor">#include</span> <span class="special">&lt;</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">multiprecision</span><span class="special">/</span><span class="identifier">cpp_int</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">&gt;</span>
<span class="keyword">namespace</span> <span class="identifier">mp</span> <span class="special">=</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">multiprecision</span><span class="special">;</span> <span class="comment">// Reduce the typing a bit later...</span>
<span class="identifier">mp</span><span class="special">::</span><span class="identifier">int128_t</span> <span class="identifier">a</span><span class="special">(</span><span class="number">3</span><span class="special">),</span> <span class="identifier">b</span><span class="special">(</span><span class="number">4</span><span class="special">);</span>
<span class="identifier">mp</span><span class="special">::</span><span class="identifier">int512_t</span> <span class="identifier">c</span><span class="special">(</span><span class="number">50</span><span class="special">),</span> <span class="identifier">d</span><span class="special">;</span>
<span class="identifier">d</span> <span class="special">=</span> <span class="identifier">c</span> <span class="special">*</span> <span class="identifier">a</span><span class="special">;</span> <span class="comment">// OK, result of mixed arithmetic is an int512_t</span>
</pre>
<p>
Conversions are also allowed:
</p>
<pre class="programlisting"><span class="identifier">d</span> <span class="special">=</span> <span class="identifier">a</span><span class="special">;</span> <span class="comment">// OK, widening conversion.</span>
<span class="identifier">d</span> <span class="special">=</span> <span class="identifier">a</span> <span class="special">*</span> <span class="identifier">b</span><span class="special">;</span> <span class="comment">// OK, can convert from an expression template too.</span>
</pre>
<p>
However conversions that are inherently lossy are either declared explicit
or else forbidden altogether:
</p>
<pre class="programlisting"><span class="identifier">d</span> <span class="special">=</span> <span class="number">3.14</span><span class="special">;</span> <span class="comment">// Error implicit conversion from double not allowed.</span>
<span class="identifier">d</span> <span class="special">=</span> <span class="keyword">static_cast</span><span class="special">&lt;</span><span class="identifier">mp</span><span class="special">::</span><span class="identifier">int512_t</span><span class="special">&gt;(</span><span class="number">3.14</span><span class="special">);</span> <span class="comment">// OK explicit construction is allowed</span>
</pre>
<p>
Mixed arithmetic will fail if the conversion is either ambiguous or explicit:
</p>
<pre class="programlisting"><span class="identifier">number</span><span class="special">&lt;</span><span class="identifier">cpp_int_backend</span><span class="special">&lt;&gt;,</span> <span class="identifier">et_off</span><span class="special">&gt;</span> <span class="identifier">a</span><span class="special">(</span><span class="number">2</span><span class="special">);</span>
<span class="identifier">number</span><span class="special">&lt;</span><span class="identifier">cpp_int_backend</span><span class="special">&lt;&gt;,</span> <span class="identifier">et_on</span><span class="special">&gt;</span> <span class="identifier">b</span><span class="special">(</span><span class="number">3</span><span class="special">);</span>
<span class="identifier">b</span> <span class="special">=</span> <span class="identifier">a</span> <span class="special">*</span> <span class="identifier">b</span><span class="special">;</span> <span class="comment">// Error, implicit conversion could go either way.</span>
<span class="identifier">b</span> <span class="special">=</span> <span class="identifier">a</span> <span class="special">*</span> <span class="number">3.14</span><span class="special">;</span> <span class="comment">// Error, no operator overload if the conversion would be explicit.</span>
</pre>
<h5>
<a name="boost_multiprecision.intro.h1"></a>
<span class="phrase"><a name="boost_multiprecision.intro.move_semantics"></a></span><a class="link" href="intro.html#boost_multiprecision.intro.move_semantics">Move
Semantics</a>
</h5>
<p>
On compilers that support rvalue-references, class <code class="computeroutput"><span class="identifier">number</span></code>
is move-enabled if the underlying backend is.
</p>
<p>
In addition the non-expression template operator overloads (see below) are
move aware and have overloads that look something like:
</p>
<pre class="programlisting"><span class="keyword">template</span> <span class="special">&lt;</span><span class="keyword">class</span> <span class="identifier">B</span><span class="special">&gt;</span>
<span class="identifier">number</span><span class="special">&lt;</span><span class="identifier">B</span><span class="special">,</span> <span class="identifier">et_off</span><span class="special">&gt;</span> <span class="keyword">operator</span> <span class="special">+</span> <span class="special">(</span><span class="identifier">number</span><span class="special">&lt;</span><span class="identifier">B</span><span class="special">,</span> <span class="identifier">et_off</span><span class="special">&gt;&amp;&amp;</span> <span class="identifier">a</span><span class="special">,</span> <span class="keyword">const</span> <span class="identifier">number</span><span class="special">&lt;</span><span class="identifier">B</span><span class="special">,</span> <span class="identifier">et_off</span><span class="special">&gt;&amp;</span> <span class="identifier">b</span><span class="special">)</span>
<span class="special">{</span>
<span class="keyword">return</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">move</span><span class="special">(</span><span class="identifier">a</span> <span class="special">+=</span> <span class="identifier">b</span><span class="special">);</span>
<span class="special">}</span>
</pre>
<p>
These operator overloads ensure that many expressions can be evaluated without
actually generating any temporaries. However, there are still many simple expressions
such as
</p>
<pre class="programlisting"><span class="identifier">a</span> <span class="special">=</span> <span class="identifier">b</span> <span class="special">*</span> <span class="identifier">c</span><span class="special">;</span>
</pre>
<p>
which don't noticeably benefit from move support. Therefore, optimal performance
comes from having both move-support, and expression templates enabled.
</p>
<p>
Note that while "moved-from" objects are left in a sane state, they
have an unspecified value, and the only permitted operations on them are destruction
or the assignment of a new value. Any other operation should be considered
a programming error and all of our backends will trigger an assertion if any
other operation is attempted. This behavior allows for optimal performance
on move-construction (i.e. no allocation required, we just take ownership of
the existing object's internal state), while maintaining usability in the standard
library containers.
</p>
<h5>
<a name="boost_multiprecision.intro.h2"></a>
<span class="phrase"><a name="boost_multiprecision.intro.expression_templates"></a></span><a class="link" href="intro.html#boost_multiprecision.intro.expression_templates">Expression
Templates</a>
</h5>
<p>
Class <code class="computeroutput"><span class="identifier">number</span></code> is expression-template-enabled:
that means that rather than having a multiplication operator that looks like
this:
</p>
<pre class="programlisting"><span class="keyword">template</span> <span class="special">&lt;</span><span class="keyword">class</span> <span class="identifier">Backend</span><span class="special">&gt;</span>
<span class="identifier">number</span><span class="special">&lt;</span><span class="identifier">Backend</span><span class="special">&gt;</span> <span class="keyword">operator</span> <span class="special">*</span> <span class="special">(</span><span class="keyword">const</span> <span class="identifier">number</span><span class="special">&lt;</span><span class="identifier">Backend</span><span class="special">&gt;&amp;</span> <span class="identifier">a</span><span class="special">,</span> <span class="keyword">const</span> <span class="identifier">number</span><span class="special">&lt;</span><span class="identifier">Backend</span><span class="special">&gt;&amp;</span> <span class="identifier">b</span><span class="special">)</span>
<span class="special">{</span>
<span class="identifier">number</span><span class="special">&lt;</span><span class="identifier">Backend</span><span class="special">&gt;</span> <span class="identifier">result</span><span class="special">(</span><span class="identifier">a</span><span class="special">);</span>
<span class="identifier">result</span> <span class="special">*=</span> <span class="identifier">b</span><span class="special">;</span>
<span class="keyword">return</span> <span class="identifier">result</span><span class="special">;</span>
<span class="special">}</span>
</pre>
<p>
Instead the operator looks more like this:
</p>
<pre class="programlisting"><span class="keyword">template</span> <span class="special">&lt;</span><span class="keyword">class</span> <span class="identifier">Backend</span><span class="special">&gt;</span>
<span class="emphasis"><em>unmentionable-type</em></span> <span class="keyword">operator</span> <span class="special">*</span> <span class="special">(</span><span class="keyword">const</span> <span class="identifier">number</span><span class="special">&lt;</span><span class="identifier">Backend</span><span class="special">&gt;&amp;</span> <span class="identifier">a</span><span class="special">,</span> <span class="keyword">const</span> <span class="identifier">number</span><span class="special">&lt;</span><span class="identifier">Backend</span><span class="special">&gt;&amp;</span> <span class="identifier">b</span><span class="special">);</span>
</pre>
<p>
Where the '<span class="emphasis"><em>unmentionable</em></span>' return type is an implementation
detail that, rather than containing the result of the multiplication, contains
instructions on how to compute the result. In effect it's just a pair of references
to the arguments of the function, plus some compile-time information that stores
what the operation is.
</p>
<p>
The great advantage of this method is the <span class="emphasis"><em>elimination of temporaries</em></span>:
for example, the "naive" implementation of <code class="computeroutput"><span class="keyword">operator</span><span class="special">*</span></code> above, requires one temporary for computing
the result, and at least another one to return it. It's true that sometimes
this overhead can be reduced by using move-semantics, but it can't be eliminated
completely. For example, lets suppose we're evaluating a polynomial via Horner's
method, something like this:
</p>
<pre class="programlisting"><span class="identifier">T</span> <span class="identifier">a</span><span class="special">[</span><span class="number">7</span><span class="special">]</span> <span class="special">=</span> <span class="special">{</span> <span class="comment">/* some values */</span> <span class="special">};</span>
<span class="comment">//....</span>
<span class="identifier">y</span> <span class="special">=</span> <span class="special">(((((</span><span class="identifier">a</span><span class="special">[</span><span class="number">6</span><span class="special">]</span> <span class="special">*</span> <span class="identifier">x</span> <span class="special">+</span> <span class="identifier">a</span><span class="special">[</span><span class="number">5</span><span class="special">])</span> <span class="special">*</span> <span class="identifier">x</span> <span class="special">+</span> <span class="identifier">a</span><span class="special">[</span><span class="number">4</span><span class="special">])</span> <span class="special">*</span> <span class="identifier">x</span> <span class="special">+</span> <span class="identifier">a</span><span class="special">[</span><span class="number">3</span><span class="special">])</span> <span class="special">*</span> <span class="identifier">x</span> <span class="special">+</span> <span class="identifier">a</span><span class="special">[</span><span class="number">2</span><span class="special">])</span> <span class="special">*</span> <span class="identifier">x</span> <span class="special">+</span> <span class="identifier">a</span><span class="special">[</span><span class="number">1</span><span class="special">])</span> <span class="special">*</span> <span class="identifier">x</span> <span class="special">+</span> <span class="identifier">a</span><span class="special">[</span><span class="number">0</span><span class="special">];</span>
</pre>
<p>
If type <code class="computeroutput"><span class="identifier">T</span></code> is a <code class="computeroutput"><span class="identifier">number</span></code>, then this expression is evaluated
<span class="emphasis"><em>without creating a single temporary value</em></span>. In contrast,
if we were using the <a href="http://math.berkeley.edu/~wilken/code/gmpfrxx/" target="_top">mpfr_class</a>
C++ wrapper for <a href="http://www.mpfr.org" target="_top">MPFR</a> - then this expression
would result in no less than 11 temporaries (this is true even though <a href="http://math.berkeley.edu/~wilken/code/gmpfrxx/" target="_top">mpfr_class</a> does
use expression templates to reduce the number of temporaries somewhat). Had
we used an even simpler wrapper around <a href="http://www.mpfr.org" target="_top">MPFR</a>
like <a href="http://www.holoborodko.com/pavel/mpfr/" target="_top">mpreal</a> things
would have been even worse and no less that 24 temporaries are created for
this simple expression (note - we actually measure the number of memory allocations
performed rather than the number of temporaries directly, note also that the
<a href="http://gmplib.org/manual/C_002b_002b-Interface-Floats.html#C_002b_002b-Interface-Floats" target="_top">mpf_class</a>
wrapper that will be supplied with GMP-5.1 reduces the number of temporaries
to pretty much zero). Note that if we compile with expression templates disabled
and rvalue-reference support on, then actually still have no wasted memory
allocations as even though temporaries are created, their contents are moved
rather than copied. <a href="#ftn.boost_multiprecision.intro.f0" class="footnote" name="boost_multiprecision.intro.f0"><sup class="footnote">[1]</sup></a>
</p>
<div class="important"><table border="0" summary="Important">
<tr>
<td rowspan="2" align="center" valign="top" width="25"><img alt="[Important]" src="../../../../../doc/src/images/important.png"></td>
<th align="left">Important</th>
</tr>
<tr><td align="left" valign="top">
<p>
Expression templates can radically reorder the operations in an expression,
for example:
</p>
<p>
a = (b * c) * a;
</p>
<p>
Will get transformed into:
</p>
<p>
a *= c; a *= b;
</p>
<p>
If this is likely to be an issue for a particular application, then they
should be disabled.
</p>
</td></tr>
</table></div>
<p>
This library also extends expression template support to standard library functions
like <code class="computeroutput"><span class="identifier">abs</span></code> or <code class="computeroutput"><span class="identifier">sin</span></code>
with <code class="computeroutput"><span class="identifier">number</span></code> arguments. This
means that an expression such as:
</p>
<pre class="programlisting"><span class="identifier">y</span> <span class="special">=</span> <span class="identifier">abs</span><span class="special">(</span><span class="identifier">x</span><span class="special">);</span>
</pre>
<p>
can be evaluated without a single temporary being calculated. Even expressions
like:
</p>
<pre class="programlisting"><span class="identifier">y</span> <span class="special">=</span> <span class="identifier">sin</span><span class="special">(</span><span class="identifier">x</span><span class="special">);</span>
</pre>
<p>
get this treatment, so that variable 'y' is used as "working storage"
within the implementation of <code class="computeroutput"><span class="identifier">sin</span></code>,
thus reducing the number of temporaries used by one. Of course, should you
write:
</p>
<pre class="programlisting"><span class="identifier">x</span> <span class="special">=</span> <span class="identifier">sin</span><span class="special">(</span><span class="identifier">x</span><span class="special">);</span>
</pre>
<p>
Then we clearly can't use <code class="computeroutput"><span class="identifier">x</span></code>
as working storage during the calculation, so then a temporary variable is
created in this case.
</p>
<p>
Given the comments above, you might be forgiven for thinking that expression-templates
are some kind of universal-panacea: sadly though, all tricks like this have
their downsides. For one thing, expression template libraries like this one,
tend to be slower to compile than their simpler cousins, they're also harder
to debug (should you actually want to step through our code!), and rely on
compiler optimizations being turned on to give really good performance. Also,
since the return type from expressions involving <code class="computeroutput"><span class="identifier">number</span></code>s
is an "unmentionable implementation detail", you have to be careful
to cast the result of an expression to the actual number type when passing
an expression to a template function. For example, given:
</p>
<pre class="programlisting"><span class="keyword">template</span> <span class="special">&lt;</span><span class="keyword">class</span> <span class="identifier">T</span><span class="special">&gt;</span>
<span class="keyword">void</span> <span class="identifier">my_proc</span><span class="special">(</span><span class="keyword">const</span> <span class="identifier">T</span><span class="special">&amp;);</span>
</pre>
<p>
Then calling:
</p>
<pre class="programlisting"><span class="identifier">my_proc</span><span class="special">(</span><span class="identifier">a</span><span class="special">+</span><span class="identifier">b</span><span class="special">);</span>
</pre>
<p>
Will very likely result in obscure error messages inside the body of <code class="computeroutput"><span class="identifier">my_proc</span></code> - since we've passed it an expression
template type, and not a number type. Instead we probably need:
</p>
<pre class="programlisting"><span class="identifier">my_proc</span><span class="special">(</span><span class="identifier">my_number_type</span><span class="special">(</span><span class="identifier">a</span><span class="special">+</span><span class="identifier">b</span><span class="special">));</span>
</pre>
<p>
Having said that, these situations don't occur that often - or indeed not at
all for non-template functions. In addition, all the functions in the Boost.Math
library will automatically convert expression-template arguments to the underlying
number type without you having to do anything, so:
</p>
<pre class="programlisting"><span class="identifier">mpfr_float_100</span> <span class="identifier">a</span><span class="special">(</span><span class="number">20</span><span class="special">),</span> <span class="identifier">delta</span><span class="special">(</span><span class="number">0.125</span><span class="special">);</span>
<span class="identifier">boost</span><span class="special">::</span><span class="identifier">math</span><span class="special">::</span><span class="identifier">gamma_p</span><span class="special">(</span><span class="identifier">a</span><span class="special">,</span> <span class="identifier">a</span> <span class="special">+</span> <span class="identifier">delta</span><span class="special">);</span>
</pre>
<p>
Will work just fine, with the <code class="computeroutput"><span class="identifier">a</span> <span class="special">+</span> <span class="identifier">delta</span></code> expression
template argument getting converted to an <code class="computeroutput"><span class="identifier">mpfr_float_100</span></code>
internally by the Boost.Math library.
</p>
<div class="caution"><table border="0" summary="Caution">
<tr>
<td rowspan="2" align="center" valign="top" width="25"><img alt="[Caution]" src="../../../../../doc/src/images/caution.png"></td>
<th align="left">Caution</th>
</tr>
<tr><td align="left" valign="top">
<p>
In C++11 you should never store an expression template using:
</p>
<p>
<code class="computeroutput"><span class="keyword">auto</span> <span class="identifier">my_expression</span>
<span class="special">=</span> <span class="identifier">a</span> <span class="special">+</span> <span class="identifier">b</span> <span class="special">-</span>
<span class="identifier">c</span><span class="special">;</span></code>
</p>
<p>
unless you're absolutely sure that the lifetimes of <code class="computeroutput"><span class="identifier">a</span></code>,
<code class="computeroutput"><span class="identifier">b</span></code> and <code class="computeroutput"><span class="identifier">c</span></code>
will outlive that of <code class="computeroutput"><span class="identifier">my_expression</span></code>.
</p>
<p>
In fact, it is particularly easy to create dangling references by mixing
expression templates with the <code class="computeroutput"><span class="keyword">auto</span></code>
keyword, for example:
</p>
<p>
<code class="computeroutput"><span class="keyword">auto</span> <span class="identifier">val</span>
<span class="special">=</span> <span class="identifier">cpp_dec_float_50</span><span class="special">(</span><span class="string">"23.1"</span><span class="special">)</span> <span class="special">*</span> <span class="number">100</span><span class="special">;</span></code>
</p>
<p>
In this situation, the integer literal is stored directly in the expression
template - so its use is OK here - but the <code class="computeroutput"><span class="identifier">cpp_dec_float_50</span></code>
temporary is stored by reference and then destructed when the statement completes,
leaving a dangling reference.
</p>
<p>
<span class="bold"><strong><span class="emphasis"><em>If in doubt, do not ever mix expression templates
with the <code class="computeroutput"><span class="keyword">auto</span></code> keyword.</em></span></strong></span>
</p>
</td></tr>
</table></div>
<p>
And finally... the performance improvements from an expression template library
like this are often not as dramatic as the reduction in number of temporaries
would suggest. For example, if we compare this library with <a href="http://math.berkeley.edu/~wilken/code/gmpfrxx/" target="_top">mpfr_class</a>
and <a href="http://www.holoborodko.com/pavel/mpfr/" target="_top">mpreal</a>, with
all three using the underlying <a href="http://www.mpfr.org" target="_top">MPFR</a>
library at 50 decimal digits precision then we see the following typical results
for polynomial execution:
</p>
<div class="table">
<a name="boost_multiprecision.intro.evaluation_of_order_6_polynomial"></a><p class="title"><b>Table&#160;1.1.&#160;Evaluation of Order 6 Polynomial.</b></p>
<div class="table-contents"><table class="table" summary="Evaluation of Order 6 Polynomial.">
<colgroup>
<col>
<col>
<col>
</colgroup>
<thead><tr>
<th>
<p>
Library
</p>
</th>
<th>
<p>
Relative Time
</p>
</th>
<th>
<p>
Relative number of memory allocations
</p>
</th>
</tr></thead>
<tbody>
<tr>
<td>
<p>
number
</p>
</td>
<td>
<p>
1.0 (0.00957s)
</p>
</td>
<td>
<p>
1.0 (2996 total)
</p>
</td>
</tr>
<tr>
<td>
<p>
<a href="http://math.berkeley.edu/~wilken/code/gmpfrxx/" target="_top">mpfr_class</a>
</p>
</td>
<td>
<p>
1.1 (0.0102s)
</p>
</td>
<td>
<p>
4.3 (12976 total)
</p>
</td>
</tr>
<tr>
<td>
<p>
<a href="http://www.holoborodko.com/pavel/mpfr/" target="_top">mpreal</a>
</p>
</td>
<td>
<p>
1.6 (0.0151s)
</p>
</td>
<td>
<p>
9.3 (27947 total)
</p>
</td>
</tr>
</tbody>
</table></div>
</div>
<br class="table-break"><p>
As you can see, the execution time increases a lot more slowly than the number
of memory allocations. There are a number of reasons for this:
</p>
<div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; ">
<li class="listitem">
The cost of extended-precision multiplication and division is so great,
that the times taken for these tend to swamp everything else.
</li>
<li class="listitem">
The cost of an in-place multiplication (using <code class="computeroutput"><span class="keyword">operator</span><span class="special">*=</span></code>) tends to be more than an out-of-place
<code class="computeroutput"><span class="keyword">operator</span><span class="special">*</span></code>
(typically <code class="computeroutput"><span class="keyword">operator</span> <span class="special">*=</span></code>
has to create a temporary workspace to carry out the multiplication, where
as <code class="computeroutput"><span class="keyword">operator</span><span class="special">*</span></code>
can use the target variable as workspace). Since the expression templates
carry out their magic by converting out-of-place operators to in-place
ones, we necessarily take this hit. Even so the transformation is more
efficient than creating the extra temporary variable, just not by as much
as one would hope.
</li>
</ul></div>
<p>
Finally, note that <code class="computeroutput"><span class="identifier">number</span></code> takes
a second template argument, which, when set to <code class="computeroutput"><span class="identifier">et_off</span></code>
disables all the expression template machinery. The result is much faster to
compile, but slower at runtime.
</p>
<p>
We'll conclude this section by providing some more performance comparisons
between these three libraries, again, all are using <a href="http://www.mpfr.org" target="_top">MPFR</a>
to carry out the underlying arithmetic, and all are operating at the same precision
(50 decimal digits):
</p>
<div class="table">
<a name="boost_multiprecision.intro.evaluation_of_boost_math_s_besse"></a><p class="title"><b>Table&#160;1.2.&#160;Evaluation of Boost.Math's Bessel function test data</b></p>
<div class="table-contents"><table class="table" summary="Evaluation of Boost.Math's Bessel function test data">
<colgroup>
<col>
<col>
<col>
</colgroup>
<thead><tr>
<th>
<p>
Library
</p>
</th>
<th>
<p>
Relative Time
</p>
</th>
<th>
<p>
Relative Number of Memory Allocations
</p>
</th>
</tr></thead>
<tbody>
<tr>
<td>
<p>
mpfr_float_50
</p>
</td>
<td>
<p>
1.0 (5.78s)
</p>
</td>
<td>
<p>
1.0 (1611963)
</p>
</td>
</tr>
<tr>
<td>
<p>
number&lt;mpfr_float_backend&lt;50&gt;, et_off&gt;<br> (but with
rvalue reference support)
</p>
</td>
<td>
<p>
1.1 (6.29s)
</p>
</td>
<td>
<p>
2.64 (4260868)
</p>
</td>
</tr>
<tr>
<td>
<p>
<a href="http://math.berkeley.edu/~wilken/code/gmpfrxx/" target="_top">mpfr_class</a>
</p>
</td>
<td>
<p>
1.1 (6.28s)
</p>
</td>
<td>
<p>
2.45 (3948316)
</p>
</td>
</tr>
<tr>
<td>
<p>
<a href="http://www.holoborodko.com/pavel/mpfr/" target="_top">mpreal</a>
</p>
</td>
<td>
<p>
1.65 (9.54s)
</p>
</td>
<td>
<p>
8.21 (13226029)
</p>
</td>
</tr>
</tbody>
</table></div>
</div>
<br class="table-break"><div class="table">
<a name="boost_multiprecision.intro.evaluation_of_boost_math_s_non_c"></a><p class="title"><b>Table&#160;1.3.&#160;Evaluation of Boost.Math's Non-Central T distribution test data</b></p>
<div class="table-contents"><table class="table" summary="Evaluation of Boost.Math's Non-Central T distribution test data">
<colgroup>
<col>
<col>
<col>
</colgroup>
<thead><tr>
<th>
<p>
Library
</p>
</th>
<th>
<p>
Relative Time
</p>
</th>
<th>
<p>
Relative Number of Memory Allocations
</p>
</th>
</tr></thead>
<tbody>
<tr>
<td>
<p>
number
</p>
</td>
<td>
<p>
1.0 (263s)
</p>
</td>
<td>
<p>
1.0 (127710873)
</p>
</td>
</tr>
<tr>
<td>
<p>
number&lt;mpfr_float_backend&lt;50&gt;, et_off&gt;<br> (but with
rvalue reference support)
</p>
</td>
<td>
<p>
1.0 (260s)
</p>
</td>
<td>
<p>
1.2 (156797871)
</p>
</td>
</tr>
<tr>
<td>
<p>
<a href="http://math.berkeley.edu/~wilken/code/gmpfrxx/" target="_top">mpfr_class</a>
</p>
</td>
<td>
<p>
1.1 (287s)
</p>
</td>
<td>
<p>
2.1 (268336640)
</p>
</td>
</tr>
<tr>
<td>
<p>
<a href="http://www.holoborodko.com/pavel/mpfr/" target="_top">mpreal</a>
</p>
</td>
<td>
<p>
1.5 (389s)
</p>
</td>
<td>
<p>
3.6 (466960653)
</p>
</td>
</tr>
</tbody>
</table></div>
</div>
<br class="table-break"><p>
The above results were generated on Win32 compiling with Visual C++ 2010, all
optimizations on (/Ox), with MPFR 3.0 and MPIR 2.3.0.
</p>
<div class="footnotes">
<br><hr style="width:100; text-align:left;margin-left: 0">
<div id="ftn.boost_multiprecision.intro.f0" class="footnote"><p><a href="#boost_multiprecision.intro.f0" class="para"><sup class="para">[1] </sup></a>
The actual number generated will depend on the compiler, how well it optimizes
the code, and whether it supports rvalue references. The number of 11 temporaries
was generated with Visual C++ 2010.
</p></div>
</div>
</div>
<table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr>
<td align="left"></td>
<td align="right"><div class="copyright-footer">Copyright &#169; 2002-2019 John Maddock
and Christopher Kormanyos<p>
Distributed under the Boost Software License, Version 1.0. (See accompanying
file LICENSE_1_0.txt or copy at <a href="http://www.boost.org/LICENSE_1_0.txt" target="_top">http://www.boost.org/LICENSE_1_0.txt</a>)
</p>
</div></td>
</tr></table>
<hr>
<div class="spirit-nav">
<a accesskey="p" href="../index.html"><img src="../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../index.html"><img src="../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="tut.html"><img src="../../../../../doc/src/images/next.png" alt="Next"></a>
</div>
</body>
</html>