178 lines
18 KiB
HTML
178 lines
18 KiB
HTML
<html>
|
|
<head>
|
|
<meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
|
|
<title>Using Automatic Type Promotion</title>
|
|
<link rel="stylesheet" href="../boostbook.css" type="text/css">
|
|
<meta name="generator" content="DocBook XSL Stylesheets V1.79.1">
|
|
<link rel="home" href="../index.html" title="Safe Numerics">
|
|
<link rel="up" href="../eliminate_runtime_penalty.html" title="Eliminating Runtime Penalty">
|
|
<link rel="prev" href="2.html" title="Using safe_range and safe_literal">
|
|
<link rel="next" href="3.html" title="Mixing Approaches">
|
|
</head>
|
|
<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
|
|
<table cellpadding="2" width="100%"><tr>
|
|
<td valign="top"><img href="index.html" height="164px" src="pre-boost.jpg" alt="Library Documentation Index"></td>
|
|
<td><h2>Safe Numerics</h2></td>
|
|
</tr></table>
|
|
<div class="spirit-nav">
|
|
<a accesskey="p" href="2.html"><img src="../images/prev.png" alt="Prev"></a><a accesskey="u" href="../eliminate_runtime_penalty.html"><img src="../images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../images/home.png" alt="Home"></a><a accesskey="n" href="3.html"><img src="../images/next.png" alt="Next"></a>
|
|
</div>
|
|
<div class="section">
|
|
<div class="titlepage"><div><div><h3 class="title">
|
|
<a name="safe_numerics.eliminate_runtime_penalty.1"></a>Using Automatic Type Promotion</h3></div></div></div>
|
|
<p>The C++ standard describes how binary operations on different
|
|
integer types are handled. Here is a simplified version of the
|
|
rules:</p>
|
|
<div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; ">
|
|
<li class="listitem"><p>promote any operand smaller than <code class="computeroutput">int</code> to an
|
|
<code class="computeroutput">int</code> or <code class="computeroutput">unsigned int</code>.</p></li>
|
|
<li class="listitem"><p>if the size of the signed operand is larger than the size of the
|
|
signed operand, the type of the result will be signed. Otherwise, the
|
|
type of the result will be unsigned.</p></li>
|
|
<li class="listitem"><p>Convert the type each operand to the type of the result,
|
|
expanding the size as necessary.</p></li>
|
|
<li class="listitem"><p>Perform the operation the two resultant operands.</p></li>
|
|
</ul></div>
|
|
<p>So the type of the result of some binary operation may be different
|
|
than the types of either or both of the original operands.</p>
|
|
<p>If the values are large, the result can exceed the size that the
|
|
resulting integer type can hold. This is what we call "overflow". The
|
|
C/C++ standard characterizes this as undefined behavior and leaves to
|
|
compiler implementors the decision as to how such a situation will be
|
|
handled. Usually, this means just truncating the result to fit into the
|
|
result type - which sometimes will make the result arithmetically
|
|
incorrect. However, depending on the compiler and compile time switch
|
|
settings, such cases may result in some sort of run time exception or
|
|
silently producing some arbitrary result.</p>
|
|
<p>The complete signature for a safe integer type is:</p>
|
|
<pre class="programlisting"><span class="keyword">template</span> <span class="special"><</span>
|
|
<span class="keyword">class</span> <span class="identifier">T</span><span class="special">,</span> <span class="comment">// underlying integer type</span>
|
|
<span class="keyword">class</span> <span class="identifier">P</span> <span class="special">=</span> <span class="identifier">native</span><span class="special">,</span> <span class="comment">// type promotion policy class</span>
|
|
<span class="keyword">class</span> <span class="identifier">E</span> <span class="special">=</span> <span class="identifier">default_exception_policy</span> <span class="comment">// error handling policy class</span>
|
|
<span class="special">></span>
|
|
<span class="identifier">safe</span><span class="special">;</span>
|
|
</pre>
|
|
<p>The promotion rules for arithmetic operations are implemented in the
|
|
default <code class="computeroutput"><a class="link" href="promotion_policies/native.html" title="native">native</a></code>
|
|
type promotion policy are consistent with those of standard C++</p>
|
|
<p>Up until now, we've focused on detecting when an arithmetic error
|
|
occurs and invoking an exception or other kind of error handler.</p>
|
|
<p>But now we look at another option. Using the <a class="link" href="promotion_policies/automatic.html" title="automatic"><code class="computeroutput">automatic</code></a>
|
|
type promotion policy, we can change the rules of C++ arithmetic for safe
|
|
types to something like the following:</p>
|
|
<div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; ">
|
|
<li class="listitem"><p>for any C++ numeric type, we know from <a href="http://en.cppreference.com/w/cpp/types/numeric_limits" target="_top"><code class="computeroutput">std::numeric_limits</code></a>
|
|
what the maximum and minimum values that a variable can be - this
|
|
defines a closed interval.</p></li>
|
|
<li class="listitem"><p>For any binary operation on these types, we can calculate the
|
|
interval of the result at compile time.</p></li>
|
|
<li class="listitem">
|
|
<p>From this interval we can select a new type which can be
|
|
guaranteed to hold the result and use this for the calculation. This
|
|
is more or less equivalent to the following code:</p>
|
|
<pre class="programlisting"><span class="keyword">int</span> <span class="identifier">x</span><span class="special">,</span> <span class="identifier">y</span><span class="special">;</span>
|
|
<span class="keyword">int</span> <span class="identifier">z</span> <span class="special">=</span> <span class="identifier">x</span> <span class="special">+</span> <span class="identifier">y</span> <span class="comment">// could overflow</span>
|
|
<span class="comment">// so replace with the following:</span>
|
|
<span class="keyword">int</span> <span class="identifier">x</span><span class="special">,</span> <span class="identifier">y</span><span class="special">;</span>
|
|
<span class="keyword">long</span> <span class="identifier">z</span> <span class="special">=</span> <span class="special">(</span><span class="keyword">long</span><span class="special">)</span><span class="identifier">x</span> <span class="special">+</span> <span class="special">(</span><span class="keyword">long</span><span class="special">)</span><span class="identifier">y</span><span class="special">;</span> <span class="comment">// can never overflow</span></pre>
|
|
<p>One could do this by editing his code manually as above, but
|
|
such a task would be tedious, error prone, non-portable and leave
|
|
the resulting code hard to read and verify. Using the <a class="link" href="promotion_policies/automatic.html" title="automatic"><code class="computeroutput">automatic</code></a>
|
|
type promotion policy will achieve the equivalent result without
|
|
these problems.</p>
|
|
</li>
|
|
</ul></div>
|
|
<p>When using the <a class="link" href="promotion_policies/automatic.html" title="automatic"><code class="computeroutput">automatic</code></a>
|
|
type promotion policy, with a given a binary operation, we silently
|
|
promote the types of the operands to a wider result type so the result
|
|
cannot overflow. This is a fundamental departure from the C++ Standard
|
|
behavior.</p>
|
|
<p>If the interval of the result cannot be guaranteed to fit in the
|
|
largest type that the machine can handle (usually 64 bits these days), the
|
|
largest available integer type with the correct result sign is used. So
|
|
even with our "automatic" type promotion scheme, it's still possible to
|
|
overflow. So while our <a class="link" href="promotion_policies/automatic.html" title="automatic"><code class="computeroutput">automatic</code></a>
|
|
type promotion policy might eliminate exceptions in our example above, it
|
|
wouldn't be guaranteed to eliminate them for all programs.</p>
|
|
<p>Using the <a class="link" href="exception_policies.html#safe_numerics.exception_policies.loose_trap_policy"><code class="computeroutput">loose_trap_policy</code></a>
|
|
exception policy will produce a compile time error anytime it's possible
|
|
for an error to occur.</p>
|
|
<p>This small example illustrates how to use automatic type promotion
|
|
to eliminate all runtime penalty.</p>
|
|
<pre class="programlisting"><span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">iostream</span><span class="special">></span>
|
|
|
|
<span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">safe_numerics</span><span class="special">/</span><span class="identifier">safe_integer</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span>
|
|
<span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">safe_numerics</span><span class="special">/</span><span class="identifier">exception_policies</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span>
|
|
<span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">safe_numerics</span><span class="special">/</span><span class="identifier">automatic</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span>
|
|
<span class="preprocessor">#include</span> <span class="string">"safe_format.hpp"</span> <span class="comment">// prints out range and value of any type</span>
|
|
|
|
<span class="keyword">using</span> <span class="identifier">safe_t</span> <span class="special">=</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">safe_numerics</span><span class="special">::</span><span class="identifier">safe</span><span class="special"><</span>
|
|
<span class="keyword">int</span><span class="special">,</span>
|
|
<span class="identifier">boost</span><span class="special">::</span><span class="identifier">safe_numerics</span><span class="special">::</span><span class="identifier">automatic</span><span class="special">,</span> <span class="comment">// note use of "automatic" policy!!!</span>
|
|
<span class="identifier">boost</span><span class="special">::</span><span class="identifier">safe_numerics</span><span class="special">::</span><span class="identifier">loose_trap_policy</span>
|
|
<span class="special">></span><span class="special">;</span>
|
|
|
|
<span class="keyword">int</span> <span class="identifier">main</span><span class="special">(</span><span class="keyword">int</span><span class="special">,</span> <span class="keyword">const</span> <span class="keyword">char</span> <span class="special">*</span><span class="special">[</span><span class="special">]</span><span class="special">)</span><span class="special">{</span>
|
|
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special"><<</span> <span class="string">"example 82:\n"</span><span class="special">;</span>
|
|
<span class="identifier">safe_t</span> <span class="identifier">x</span><span class="special">(</span><span class="identifier">INT_MAX</span><span class="special">)</span><span class="special">;</span>
|
|
<span class="identifier">safe_t</span> <span class="identifier">y</span> <span class="special">=</span> <span class="number">2</span><span class="special">;</span>
|
|
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special"><<</span> <span class="string">"x = "</span> <span class="special"><<</span> <span class="identifier">safe_format</span><span class="special">(</span><span class="identifier">x</span><span class="special">)</span> <span class="special"><<</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span>
|
|
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special"><<</span> <span class="string">"y = "</span> <span class="special"><<</span> <span class="identifier">safe_format</span><span class="special">(</span><span class="identifier">y</span><span class="special">)</span> <span class="special"><<</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span>
|
|
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special"><<</span> <span class="string">"x + y = "</span> <span class="special"><<</span> <span class="identifier">safe_format</span><span class="special">(</span><span class="identifier">x</span> <span class="special">+</span> <span class="identifier">y</span><span class="special">)</span> <span class="special"><<</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span>
|
|
<span class="keyword">return</span> <span class="number">0</span><span class="special">;</span>
|
|
<span class="special">}</span>
|
|
|
|
</pre>
|
|
<div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; ">
|
|
<li class="listitem"><p>the <a class="link" href="promotion_policies/automatic.html" title="automatic"><code class="computeroutput">automatic</code></a>
|
|
type promotion policy has rendered the result of the sum of two
|
|
<code class="computeroutput">integers</code> as a <code class="computeroutput">safe<long</code>> type.</p></li>
|
|
<li class="listitem"><p>our program compiles without error - even when using the <a class="link" href="exception_policies.html#safe_numerics.exception_policies.loose_trap_policy"><code class="computeroutput">loose_trap_policy</code></a>
|
|
exception policy. This is because since a <code class="computeroutput">long</code> can always
|
|
hold the result of the sum of two integers.</p></li>
|
|
<li class="listitem"><p>We do not need to use the <code class="computeroutput">try/catch</code> idiom to handle
|
|
arithmetic errors - we will have no exceptions.</p></li>
|
|
<li class="listitem"><p>We only needed to change two lines of code to achieve our goal
|
|
of guaranteed program correctness with no runtime penalty.</p></li>
|
|
</ul></div>
|
|
<p>The above program produces the following output:</p>
|
|
<pre class="screen">example 82:
|
|
x = <int>[-2147483648,2147483647] = 2147483647
|
|
y = <int>[-2147483648,2147483647] = 2
|
|
x + y = <long>[-4294967296,4294967294] = 2147483649
|
|
</pre>
|
|
<p>Note that if any time in the future we were to change
|
|
safe<int> to safe<long long> the program could now overflow.
|
|
But since we're using <a class="link" href="exception_policies.html#safe_numerics.exception_policies.loose_trap_policy"><code class="computeroutput">loose_trap_policy</code></a>
|
|
the modified program would fail to compile. At this point we'd have to
|
|
alter our yet program again to eliminate run time penalty or set aside our
|
|
goal of zero run time overhead and change the exception policy to <a class="link" href="exception_policies.html#safe_numerics.exception_policies.default_exception_policy"><code class="computeroutput">default_exception_policy</code></a>
|
|
.</p>
|
|
<p>Note that once we use automatic type promotion, our programming
|
|
language isn't C/C++ anymore. So don't be tempted to so something like the
|
|
following:</p>
|
|
<pre class="programlisting"><span class="comment">// DON'T DO THIS !</span>
|
|
<span class="preprocessor">#if</span> <span class="identifier">defined</span><span class="special">(</span><span class="identifier">NDEBUG</span><span class="special">)</span>
|
|
<span class="keyword">using</span> <span class="identifier">safe_t</span> <span class="special">=</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">numeric</span><span class="special">::</span><span class="identifier">safe</span><span class="special"><</span>
|
|
<span class="keyword">int</span><span class="special">,</span>
|
|
<span class="identifier">boost</span><span class="special">::</span><span class="identifier">numeric</span><span class="special">::</span><span class="identifier">automatic</span><span class="special">,</span> <span class="comment">// note use of "automatic" policy!!!</span>
|
|
<span class="identifier">boost</span><span class="special">::</span><span class="identifier">numeric</span><span class="special">::</span><span class="identifier">loose_trap_policy</span>
|
|
<span class="special">></span><span class="special">;</span>
|
|
<span class="preprocessor">#else</span>
|
|
<span class="keyword">using</span> <span class="identifier">safe_t</span> <span class="special">=</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">numeric</span><span class="special">::</span><span class="identifier">safe</span><span class="special"><</span><span class="keyword">int</span><span class="special">></span><span class="special">;</span>
|
|
<span class="preprocessor">#endif</span>
|
|
</pre>
|
|
</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 © 2012-2018 Robert Ramey<p><a href="http://www.boost.org/LICENSE_1_0.txt" target="_top">Subject to Boost
|
|
Software License</a></p>
|
|
</div></td>
|
|
</tr></table>
|
|
<hr>
|
|
<div class="spirit-nav">
|
|
<a accesskey="p" href="2.html"><img src="../images/prev.png" alt="Prev"></a><a accesskey="u" href="../eliminate_runtime_penalty.html"><img src="../images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../images/home.png" alt="Home"></a><a accesskey="n" href="3.html"><img src="../images/next.png" alt="Next"></a>
|
|
</div>
|
|
</body>
|
|
</html>
|