mirror of
https://github.com/boostorg/safe_numerics.git
synced 2026-02-12 12:22:16 +00:00
171 lines
7.6 KiB
HTML
171 lines
7.6 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="Parameter checking is too expensive">
|
|
<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++ just truncates the result to fit into the result type - which makes
|
|
the result arithmetically incorrect. Up until now, we've focused on
|
|
detecting when this happens and invoking an interrupt or other kind of
|
|
error handler. But now we look at another option. Using the "automatic"
|
|
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" 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.</p></li>
|
|
<li class="listitem"><p>From this 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, 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 sort, 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 "../include/safe_range.hpp"
|
|
#include "../include/automatic.hpp"
|
|
|
|
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
|
|
>;
|
|
|
|
// I can't figure out how to overload os << for safe_t
|
|
// we use the following workaround there
|
|
|
|
// wrap a safe_t in a "formatted" wrapper
|
|
template<typename T>
|
|
struct formatted {
|
|
using wrapped_type = T;
|
|
const T & m_t;
|
|
formatted(const T & t) :
|
|
m_t(t)
|
|
{}
|
|
};
|
|
|
|
template<typename T>
|
|
auto make_formatted(const T & t){
|
|
return formatted<T>(t);
|
|
}
|
|
|
|
// now (fully) specialize output of safe types wrapped in formatted
|
|
template<
|
|
class T,
|
|
T Min,
|
|
T Max,
|
|
class P, // promotion polic
|
|
class E // exception policy
|
|
>
|
|
std::ostream & operator<<(
|
|
std::ostream & os,
|
|
const formatted<boost::numeric::safe_base<T, Min, Max, P, E>> & f
|
|
){
|
|
using safe_type = typename formatted<boost::numeric::safe_base<T, Min, Max, P, E> >::wrapped_type;
|
|
return os
|
|
<< "["
|
|
<< std::numeric_limits<safe_type>::min() << ","
|
|
<< std::numeric_limits<safe_type>::max() << "] = "
|
|
<< f.m_t;
|
|
}
|
|
|
|
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{
|
|
int status;
|
|
const safe_t<-64, 63> x(1);
|
|
std::cout << abi::__cxa_demangle(typeid(x).name(),0,0,&status) << '\n';
|
|
|
|
std::cout << "x" << make_formatted(x) << std::endl;
|
|
safe_t<-64, 63> y;
|
|
y = 2;
|
|
std::cout << "y" << make_formatted(y) << std::endl;
|
|
auto z = x + y;
|
|
std::cout << "(x + y)" << make_formatted(z) << std::endl;
|
|
|
|
std::cout << "(x - y)" << make_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>
|
|
</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>
|