mirror of
https://github.com/boostorg/safe_numerics.git
synced 2026-02-25 16:42:33 +00:00
190 lines
9.2 KiB
HTML
190 lines
9.2 KiB
HTML
<html>
|
|
<head>
|
|
<meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
|
|
<title>Eliminate Runtime Cost</title>
|
|
<link rel="stylesheet" href="../boostbook.css" type="text/css">
|
|
<meta name="generator" content="DocBook XSL Stylesheets V1.76.1">
|
|
<link rel="home" href="../index.html" title="Safe Numerics">
|
|
<link rel="up" href="../tutorial.html" title="Tutorial and Motivating Examples">
|
|
<link rel="prev" href="7.html" title="Programming by Contract is Too Slow">
|
|
<link rel="next" href="../notes.html" title="Notes">
|
|
</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="7.html"><img src="../images/prev.png" alt="Prev"></a><a accesskey="u" href="../tutorial.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="../notes.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.tutorial.8"></a>Eliminate Runtime Cost</h3></div></div></div>
|
|
<p>Our system works by checking arithmetic operations whenever they
|
|
could result in an erroneous result. 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" type="disc">
|
|
<li class="listitem"><p>promote any operand smaller than int to an int or unsigned
|
|
int.</p></li>
|
|
<li class="listitem"><p>if the signed operand is larger than the signed one, the result
|
|
will be signed, otherwise the result will be unsigned.</p></li>
|
|
<li class="listitem"><p>expand the smaller operand to the size of the larger one</p></li>
|
|
</ul></div>
|
|
<p>So the result of the sum of two integer types will result in another
|
|
integer type. If the values are large, they will exceed the size that the
|
|
resulting integer type can hold. This is what we call "overflow". Standard
|
|
C/C++ just truncates the result to fit into the result type - which makes
|
|
the result arithmetically incorrect. This behavior is consistent with the
|
|
default <a class="link" href="promotion_policy.html#safe_numerics.promotion_policy.models.native">"native" type
|
|
promotion policy</a>. Up until now, we've focused on detecting when
|
|
this happens and invoking an interrupt or other kind of error handler.
|
|
</p>
|
|
<p>But now we look at another option. Using the <a class="link" href="promotion_policy.html#safe_numerics.promotion_policy.models.automatic">"automatic" type
|
|
promotion policy</a>, we can change the rules of C++ arithmetic for
|
|
safe types to something like the following:</p>
|
|
<div class="itemizedlist"><ul class="itemizedlist" type="disc">
|
|
<li class="listitem"><p>for any C++ numeric types, we know from
|
|
<code class="computeroutput">std::numeric::limits</code> 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 determine a new safe type which can
|
|
be guarenteed to hold the result.</p></li>
|
|
<li class="listitem"><p>Since the result type is guarenteed to hold the result, there
|
|
is no need to check for errors - they can't happen !!!</p></li>
|
|
<li class="listitem"><p>The only error checking we need to do is when safe values are
|
|
initialized or assigned, but this we would have to do in any case.
|
|
So we've eliminated arithmetically incorrect results while incurring
|
|
zero runtime overhead for error checking.</p></li>
|
|
</ul></div>
|
|
<p>In short, given a binary operation, we promote the constituent types
|
|
to a larger result type which can't overflow. This is a fundamental
|
|
deparature from the C++ Standard behavior.</p>
|
|
<p>If the interval of the result cannot be contained 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. In
|
|
this case, and only this case, is runtime error checking code generated.
|
|
Depending on the application, it should be rare to generate error checking
|
|
code, and even more rare to actually invoke it.</p>
|
|
<p>This small example illustrates how to use type promotion and how it
|
|
works.</p>
|
|
<pre class="programlisting">#include <cassert>
|
|
#include <stdexcept>
|
|
#include <ostream>
|
|
#include <iostream>
|
|
#include <cxxabi.h>
|
|
#include <typeinfo>
|
|
|
|
#include "../include/safe_range.hpp"
|
|
#include "../include/automatic.hpp"
|
|
|
|
// create an output manipulator which prints variable type and limits
|
|
// as well as value
|
|
template<typename T>
|
|
struct formatted_impl {
|
|
const T & m_t;
|
|
formatted_impl(const T & t) :
|
|
m_t(t)
|
|
{}
|
|
template <class charT, class Traits>
|
|
friend std::basic_ostream<charT,Traits> &
|
|
operator<<(
|
|
std::basic_ostream<charT,Traits> & os,
|
|
const formatted_impl<T> & f
|
|
){
|
|
int status;
|
|
return os
|
|
<< "<"
|
|
<< abi::__cxa_demangle(
|
|
typeid(boost::numeric::base_value(m_t)).name(),0,0,&status
|
|
)
|
|
<< ">["
|
|
<< std::numeric_limits<T>::min() << ","
|
|
<< std::numeric_limits<T>::max() << "] = "
|
|
<< f.m_t;
|
|
}
|
|
};
|
|
|
|
template<typename T>
|
|
auto formatted(const T & t){
|
|
return formatted_impl<T>(t);
|
|
}
|
|
|
|
// create a type for holding small integers which implement automatic
|
|
// type promotion to larger types to guarentee correct results with
|
|
// zero runtime overhead !
|
|
template <
|
|
std::intmax_t Min,
|
|
std::intmax_t Max
|
|
>
|
|
using safe_t = boost::numeric::safe_signed_range<
|
|
Min,
|
|
Max,
|
|
boost::numeric::automatic,
|
|
boost::numeric::throw_exception
|
|
>;
|
|
using small_integer_t = safe_t<-24, 82>;
|
|
|
|
int main(int argc, const char * argv[]){
|
|
// problem: checking of externally produced value can be overlooked
|
|
std::cout << "example 8: ";
|
|
std::cout << "eliminate runtime overhead" << std::endl;
|
|
|
|
try{
|
|
const small_integer_t x(1);
|
|
std::cout << "x" << formatted(x) << std::endl;
|
|
small_integer_t y = 2;
|
|
std::cout << "y" << formatted(y) << std::endl;
|
|
auto z = x + y; // zero runtime overhead !
|
|
std::cout << "(x + y)" << formatted(z) << std::endl;
|
|
std::cout << "(x - y)" << formatted(x - y) << std::endl;
|
|
}
|
|
catch(std::exception e){
|
|
// none of the above should trap. Mark failure if they do
|
|
std::cout << e.what() << std::endl;
|
|
return false;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
</pre>
|
|
<p>The
|
|
above program produces the following output:</p>
|
|
<pre class="programlisting">example 8: eliminate runtime overhead
|
|
x<signed char>[-24,82] = 1
|
|
y<signed char>[-24,82] = 2
|
|
(x + y)<short>[-48,164] = 3
|
|
(x - y)<signed char>[-106,106] = -1</pre>
|
|
<p>Variables x and y
|
|
are stored as 8 bit signed integers with range specied as -24 to 82. The
|
|
result of x + y could be any value in the range -48 to 164. Since this
|
|
result can't be stored in an 8 bit signed integer, a 16 bit signed integer
|
|
is allocated. The result x - y could range from -106 to 106 so will fit in
|
|
an 8 bit signed integer is allocated. Binary operations with safe numeric
|
|
using automatic type promotion will produce other safe numeric types with
|
|
template parameters appropriate to hold the result. The resultant safe
|
|
types may have smaller or larger ranges than the parameters of the binary
|
|
operation.</p>
|
|
<p>We've used simple expressions in this illustration. But since binary
|
|
operations on safe types result in other safe types, expressions can be
|
|
made arbitrarily elaborate - just as they can be with intrinsic integer
|
|
types. That is, safe integer types are drop in replacements for intrinsic
|
|
integer types. We are guarenteed never to produce an incorrect result
|
|
regardless of how elaborate the expression might be.</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 © 2012 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="7.html"><img src="../images/prev.png" alt="Prev"></a><a accesskey="u" href="../tutorial.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="../notes.html"><img src="../images/next.png" alt="Next"></a>
|
|
</div>
|
|
</body>
|
|
</html>
|