2021-10-05 21:37:46 +02:00

276 lines
23 KiB
HTML
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Compile Time Power of a Runtime Base</title>
<link rel="stylesheet" href="../../math.css" type="text/css">
<meta name="generator" content="DocBook XSL Stylesheets V1.79.1">
<link rel="home" href="../../index.html" title="Math Toolkit 3.0.0">
<link rel="up" href="../powers.html" title="Basic Functions">
<link rel="prev" href="hypot.html" title="hypot">
<link rel="next" href="rsqrt.html" title="Reciprocal square root">
</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="hypot.html"><img src="../../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../powers.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="rsqrt.html"><img src="../../../../../../doc/src/images/next.png" alt="Next"></a>
</div>
<div class="section">
<div class="titlepage"><div><div><h3 class="title">
<a name="math_toolkit.powers.ct_pow"></a><a class="link" href="ct_pow.html" title="Compile Time Power of a Runtime Base">Compile Time Power of a Runtime
Base</a>
</h3></div></div></div>
<p>
The <code class="computeroutput"><span class="identifier">pow</span></code> function effectively
computes the compile-time integral power of a run-time base.
</p>
<h5>
<a name="math_toolkit.powers.ct_pow.h0"></a>
<span class="phrase"><a name="math_toolkit.powers.ct_pow.synopsis"></a></span><a class="link" href="ct_pow.html#math_toolkit.powers.ct_pow.synopsis">Synopsis</a>
</h5>
<p>
<a href="../../../../../../boost/math/special_functions/pow.hpp" target="_top"><code class="computeroutput"><span class="preprocessor">#include</span> <span class="special">&lt;</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">math</span><span class="special">/</span><span class="identifier">special_functions</span><span class="special">/</span><span class="identifier">pow</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">&gt;</span></code></a>
</p>
<pre class="programlisting"><span class="keyword">namespace</span> <span class="identifier">boost</span> <span class="special">{</span> <span class="keyword">namespace</span> <span class="identifier">math</span> <span class="special">{</span>
<span class="keyword">template</span> <span class="special">&lt;</span><span class="keyword">int</span> <span class="identifier">N</span><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">T</span><span class="special">&gt;</span>
<span class="keyword">constexpr</span> <a class="link" href="../result_type.html" title="Calculation of the Type of the Result"><span class="emphasis"><em>calculated-result-type</em></span></a> <span class="identifier">pow</span><span class="special">(</span><span class="identifier">T</span> <span class="identifier">base</span><span class="special">);</span>
<span class="keyword">template</span> <span class="special">&lt;</span><span class="keyword">int</span> <span class="identifier">N</span><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">T</span><span class="special">,</span> <span class="keyword">class</span> <span class="identifier">Policy</span><span class="special">&gt;</span>
<span class="keyword">constexpr</span> <a class="link" href="../result_type.html" title="Calculation of the Type of the Result"><span class="emphasis"><em>calculated-result-type</em></span></a> <span class="identifier">pow</span><span class="special">(</span><span class="identifier">T</span> <span class="identifier">base</span><span class="special">,</span> <span class="keyword">const</span> <span class="identifier">Policy</span><span class="special">&amp;</span> <span class="identifier">policy</span><span class="special">);</span>
<span class="special">}}</span>
</pre>
<h5>
<a name="math_toolkit.powers.ct_pow.h1"></a>
<span class="phrase"><a name="math_toolkit.powers.ct_pow.rationale_and_usage"></a></span><a class="link" href="ct_pow.html#math_toolkit.powers.ct_pow.rationale_and_usage">Rationale
and Usage</a>
</h5>
<p>
Computing the power of a number with an exponent that is known at compile
time is a common need for programmers. In such cases, the usual method is
to avoid the overhead implied by the <code class="computeroutput"><span class="identifier">pow</span></code>,
<code class="computeroutput"><span class="identifier">powf</span></code> and <code class="computeroutput"><span class="identifier">powl</span></code>
C functions by hardcoding an expression such as:
</p>
<pre class="programlisting"><span class="comment">// Hand-written 8th power of a 'base' variable</span>
<span class="keyword">double</span> <span class="identifier">result</span> <span class="special">=</span> <span class="identifier">base</span><span class="special">*</span><span class="identifier">base</span><span class="special">*</span><span class="identifier">base</span><span class="special">*</span><span class="identifier">base</span><span class="special">*</span><span class="identifier">base</span><span class="special">*</span><span class="identifier">base</span><span class="special">*</span><span class="identifier">base</span><span class="special">*</span><span class="identifier">base</span><span class="special">;</span>
</pre>
<p>
However, this kind of expression is not really readable (knowing the value
of the exponent involves counting the number of occurrences of <span class="emphasis"><em>base</em></span>),
error-prone (it's easy to forget an occurrence), syntactically bulky, and
non-optimal in terms of performance.
</p>
<p>
The <code class="computeroutput"><span class="identifier">pow</span></code> function of Boost.Math
helps writing this kind expression along with solving all the problems listed
above:
</p>
<pre class="programlisting"><span class="comment">// 8th power of a 'base' variable using math::pow</span>
<span class="keyword">double</span> <span class="identifier">result</span> <span class="special">=</span> <span class="identifier">pow</span><span class="special">&lt;</span><span class="number">8</span><span class="special">&gt;(</span><span class="identifier">base</span><span class="special">);</span>
</pre>
<p>
The expression is now shorter, easier to read, safer, and even faster. Indeed,
<code class="computeroutput"><span class="identifier">pow</span></code> will compute the expression
such that only log2(N) products are made for a power of N. For instance in
the example above, the resulting expression will be the same as if we had
written this, with only one computation of each identical subexpression:
</p>
<pre class="programlisting"><span class="comment">// Internal effect of pow&lt;8&gt;(base)</span>
<span class="keyword">double</span> <span class="identifier">result</span> <span class="special">=</span> <span class="special">((</span><span class="identifier">base</span><span class="special">*</span><span class="identifier">base</span><span class="special">)*(</span><span class="identifier">base</span><span class="special">*</span><span class="identifier">base</span><span class="special">))*((</span><span class="identifier">base</span><span class="special">*</span><span class="identifier">base</span><span class="special">)*(</span><span class="identifier">base</span><span class="special">*</span><span class="identifier">base</span><span class="special">));</span>
</pre>
<p>
Only 3 different products were actually computed.
</p>
<h5>
<a name="math_toolkit.powers.ct_pow.h2"></a>
<span class="phrase"><a name="math_toolkit.powers.ct_pow.return_type"></a></span><a class="link" href="ct_pow.html#math_toolkit.powers.ct_pow.return_type">Return
Type</a>
</h5>
<p>
The return type of these functions is computed using the <a class="link" href="../result_type.html" title="Calculation of the Type of the Result"><span class="emphasis"><em>result
type calculation rules</em></span></a>. For example:
</p>
<div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; ">
<li class="listitem">
If T is a <code class="computeroutput"><span class="keyword">float</span></code>, the return
type is a <code class="computeroutput"><span class="keyword">float</span></code>.
</li>
<li class="listitem">
If T is a <code class="computeroutput"><span class="keyword">long</span> <span class="keyword">double</span></code>,
the return type is a <code class="computeroutput"><span class="keyword">long</span> <span class="keyword">double</span></code>.
</li>
<li class="listitem">
Otherwise, the return type is a <code class="computeroutput"><span class="keyword">double</span></code>.
</li>
</ul></div>
<h5>
<a name="math_toolkit.powers.ct_pow.h3"></a>
<span class="phrase"><a name="math_toolkit.powers.ct_pow.constexpr"></a></span><a class="link" href="ct_pow.html#math_toolkit.powers.ct_pow.constexpr">constexpr</a>
</h5>
<p>
This function is usable in <code class="computeroutput"><span class="keyword">constexpr</span></code>
contexts from C++14 onwards.
</p>
<h5>
<a name="math_toolkit.powers.ct_pow.h4"></a>
<span class="phrase"><a name="math_toolkit.powers.ct_pow.policies"></a></span><a class="link" href="ct_pow.html#math_toolkit.powers.ct_pow.policies">Policies</a>
</h5>
<p>
The final <a class="link" href="../../policy.html" title="Chapter 21. Policies: Controlling Precision, Error Handling etc">Policy</a> argument is optional and can
be used to control the behaviour of the function: how it handles errors,
what level of precision to use etc. Refer to the <a class="link" href="../../policy.html" title="Chapter 21. Policies: Controlling Precision, Error Handling etc">policy
documentation for more details</a>.
</p>
<h5>
<a name="math_toolkit.powers.ct_pow.h5"></a>
<span class="phrase"><a name="math_toolkit.powers.ct_pow.error_handling"></a></span><a class="link" href="ct_pow.html#math_toolkit.powers.ct_pow.error_handling">Error
Handling</a>
</h5>
<p>
Two cases of errors can occur when using <code class="computeroutput"><span class="identifier">pow</span></code>:
</p>
<div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; ">
<li class="listitem">
In case of null base and negative exponent, an <a class="link" href="../error_handling.html#math_toolkit.error_handling.overflow_error">overflow_error</a>
occurs since this operation is a division by 0 (it equals to 1/0).
</li>
<li class="listitem">
In case of null base and null exponent, an <a class="link" href="../error_handling.html#math_toolkit.error_handling.indeterminate_result_error">indeterminate_result_error</a>
occurs since the result of this operation is indeterminate. Those errors
follow the <a class="link" href="../error_handling.html" title="Error Handling">general policies
of error handling in Boost.Math</a>.
</li>
</ul></div>
<p>
The default overflow error policy is <code class="computeroutput"><span class="identifier">throw_on_error</span></code>.
A call like <code class="computeroutput"><span class="identifier">pow</span><span class="special">&lt;-</span><span class="number">2</span><span class="special">&gt;(</span><span class="number">0</span><span class="special">)</span></code> will thus throw a <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">overflow_error</span></code>
exception. As shown in the link given above, other error handling policies
can be used:
</p>
<div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; ">
<li class="listitem">
<code class="computeroutput"><span class="identifier">errno_on_error</span></code>: Sets
<code class="computeroutput"><span class="special">::</span><span class="identifier">errno</span></code>
to <code class="computeroutput"><span class="identifier">ERANGE</span></code> and returns
<code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">numeric_limits</span><span class="special">&lt;</span><span class="identifier">T</span><span class="special">&gt;::</span><span class="identifier">infinity</span><span class="special">()</span></code>.
</li>
<li class="listitem">
<code class="computeroutput"><span class="identifier">ignore_error</span></code>: Returns
<code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">numeric_limits</span><span class="special">&lt;</span><span class="identifier">T</span><span class="special">&gt;::</span><span class="identifier">infinity</span><span class="special">()</span></code>.
</li>
<li class="listitem">
<code class="computeroutput"><span class="identifier">user_error</span></code>: Returns the
result of <code class="computeroutput"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">math</span><span class="special">::</span><span class="identifier">policies</span><span class="special">::</span><span class="identifier">user_overflow_error</span></code>: this function
must be defined by the user.
</li>
</ul></div>
<p>
The default indeterminate result error policy is <code class="computeroutput"><span class="identifier">ignore_error</span></code>,
which for this function returns 1 since it's the most commonly chosen result
for a power of 0. Here again, other error handling policies can be used:
</p>
<div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; ">
<li class="listitem">
<code class="computeroutput"><span class="identifier">throw_on_error</span></code>: Throws
<code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">domain_error</span></code>
</li>
<li class="listitem">
<code class="computeroutput"><span class="identifier">errno_on_error</span></code>: Sets
<code class="computeroutput"><span class="special">::</span><span class="identifier">errno</span></code>
to <code class="computeroutput"><span class="identifier">EDOM</span></code> and returns 1.
</li>
<li class="listitem">
<code class="computeroutput"><span class="identifier">user_error</span></code>: Returns the
result of <code class="computeroutput"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">math</span><span class="special">::</span><span class="identifier">policies</span><span class="special">::</span><span class="identifier">user_indeterminate_result_error</span></code>: this
function must be defined by the user.
</li>
</ul></div>
<p>
Here is an example of error handling customization where we want to specify
the result that has to be returned in case of error. We will thus use the
<code class="computeroutput"><span class="identifier">user_error</span></code> policy, by passing
as second argument an instance of an overflow_error policy templated with
<code class="computeroutput"><span class="identifier">user_error</span></code>:
</p>
<pre class="programlisting"><span class="comment">// First we open the boost::math::policies namespace and define the `user_overflow_error`</span>
<span class="comment">// by making it return the value we want in case of error (-1 here)</span>
<span class="keyword">namespace</span> <span class="identifier">boost</span> <span class="special">{</span> <span class="keyword">namespace</span> <span class="identifier">math</span> <span class="special">{</span> <span class="keyword">namespace</span> <span class="identifier">policies</span> <span class="special">{</span>
<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="identifier">T</span> <span class="identifier">user_overflow_error</span><span class="special">(</span><span class="keyword">const</span> <span class="keyword">char</span><span class="special">*,</span> <span class="keyword">const</span> <span class="keyword">char</span><span class="special">*,</span> <span class="keyword">const</span> <span class="identifier">T</span><span class="special">&amp;)</span>
<span class="special">{</span> <span class="keyword">return</span> <span class="special">-</span><span class="number">1</span><span class="special">;</span> <span class="special">}</span>
<span class="special">}}}</span>
<span class="comment">// Then we invoke pow and indicate that we want to use the user_error policy</span>
<span class="keyword">using</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">math</span><span class="special">::</span><span class="identifier">policies</span><span class="special">;</span>
<span class="keyword">double</span> <span class="identifier">result</span> <span class="special">=</span> <span class="identifier">pow</span><span class="special">&lt;-</span><span class="number">5</span><span class="special">&gt;(</span><span class="identifier">base</span><span class="special">,</span> <span class="identifier">policy</span><span class="special">&lt;</span><span class="identifier">overflow_error</span><span class="special">&lt;</span><span class="identifier">user_error</span><span class="special">&gt;</span> <span class="special">&gt;());</span>
<span class="comment">// We can now test the returned value and treat the special case if needed:</span>
<span class="keyword">if</span> <span class="special">(</span><span class="identifier">result</span> <span class="special">==</span> <span class="special">-</span><span class="number">1</span><span class="special">)</span>
<span class="special">{</span>
<span class="comment">// there was an error, do something...</span>
<span class="special">}</span>
</pre>
<p>
Another way is to redefine the default <code class="computeroutput"><span class="identifier">overflow_error</span></code>
policy by using the BOOST_MATH_OVERFLOW_ERROR_POLICY macro. Once the <code class="computeroutput"><span class="identifier">user_overflow_error</span></code> function is defined
as above, we can achieve the same result like this:
</p>
<pre class="programlisting"><span class="comment">// Redefine the default error_overflow policy</span>
<span class="preprocessor">#define</span> <span class="identifier">BOOST_MATH_OVERFLOW_ERROR_POLICY</span> <span class="identifier">user_error</span>
<span class="preprocessor">#include</span> <span class="special">&lt;</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">math</span><span class="special">/</span><span class="identifier">special_functions</span><span class="special">/</span><span class="identifier">pow</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">&gt;</span>
<span class="comment">// From this point, passing a policy in argument is no longer needed, a call like this one</span>
<span class="comment">// will return -1 in case of error:</span>
<span class="keyword">double</span> <span class="identifier">result</span> <span class="special">=</span> <span class="identifier">pow</span><span class="special">&lt;-</span><span class="number">5</span><span class="special">&gt;(</span><span class="identifier">base</span><span class="special">);</span>
</pre>
<h5>
<a name="math_toolkit.powers.ct_pow.h6"></a>
<span class="phrase"><a name="math_toolkit.powers.ct_pow.acknowledgements"></a></span><a class="link" href="ct_pow.html#math_toolkit.powers.ct_pow.acknowledgements">Acknowledgements</a>
</h5>
<p>
Bruno Lalande submitted this addition to Boost.Math.
</p>
<p>
Thanks to Joaquín López Muñoz and Scott McMurray for their help in
improving the implementation.
</p>
<h5>
<a name="math_toolkit.powers.ct_pow.h7"></a>
<span class="phrase"><a name="math_toolkit.powers.ct_pow.references"></a></span><a class="link" href="ct_pow.html#math_toolkit.powers.ct_pow.references">References</a>
</h5>
<p>
D.E. Knuth, <span class="emphasis"><em>The Art of Computer Programming, Vol. 2: Seminumerical
Algorithms</em></span>, 2nd ed., Addison-Wesley, Reading, MA, 1981
</p>
</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 © 2006-2021 Nikhar Agrawal, Anton Bikineev, Matthew Borland,
Paul A. Bristow, Marco Guazzone, Christopher Kormanyos, Hubert Holin, Bruno
Lalande, John Maddock, Evan Miller, Jeremy Murphy, Matthew Pulver, Johan Råde,
Gautam Sewani, Benjamin Sobotta, Nicholas Thompson, Thijs van den Berg, Daryle
Walker and Xiaogang Zhang<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="hypot.html"><img src="../../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../powers.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="rsqrt.html"><img src="../../../../../../doc/src/images/next.png" alt="Next"></a>
</div>
</body>
</html>