File: checking.htm

package info (click to toggle)
boost 1.33.1-10
  • links: PTS
  • area: main
  • in suites: etch, etch-m68k
  • size: 100,948 kB
  • ctags: 145,103
  • sloc: cpp: 573,492; xml: 49,055; python: 15,626; ansic: 13,588; sh: 2,099; yacc: 858; makefile: 660; perl: 427; lex: 111; csh: 6
file content (223 lines) | stat: -rw-r--r-- 11,645 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
    "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
  <link rel="stylesheet" type="text/css" href="../../../../boost.css">
  <title>Checking policies</title>
</head>

<body>
<h1>Checking policies</h1>

<p>A checking policy controls how the <code>interval</code> class will deal
with special cases like: empty intervals, infinite numbers, invalid
values.</p>

<p>For example, let's consider <code>operator+(interval, T)</code>. The
second argument could be an invalid value (for a floating-point number, it is
a NaN). What to do in such a case? First, we could say that the second
argument can never be an invalid number. Second, we could also say such a
situation can arise but is forbidden. Third, we could allow such values and
generate an empty interval when encountered. And there is many other
possibilities.</p>

<p>It is the reason why such a policy is used: there is a lot of interesting
behaviors and it would be sad to arbitrarily select one of these.</p>

<h2>Requirements</h2>

<p>The checking class should satisfy the following requirement (in the form
of an interface):</p>
<pre>/* requirements for checking policy */
struct checking
{
  static T pos_inf();
  static T neg_inf();
  static T nan();
  static bool is_nan(const T&amp;);
  static T empty_lower();
  static T empty_upper();
  static bool is_empty(const T&amp;, const T&amp;);
};</pre>

<p>The first two functions, <code>pos_inf</code> and <code>neg_inf</code>,
are invoked each time the library has to create the infinite bound of an
interval. For example, <code>interval::whole</code> computes
<code>interval(checking::neg_inf(), checking::pos_inf())</code>. If infinite
values are allowed and <code>std::numeric_limits&lt;T&gt;::infinity()</code>
returns a correct value, such a value can be used.</p>

<p>Next comes <code>nan</code>. This function is used each time a function
need to return a value of type <code>T</code> but is unable to compute it. It
only happens when one of the arguments of the function is invalid. For
example, if you ask what the median value of an empty interval is,
<code>nan</code> will be used. But please remember: <code>lower</code> and
<code>upper</code> directly return the value stocked in the interval; so, if
the interval is empty, <code>lower</code> will not answer <code>by</code> a
call to <code>checking::nan</code> (but will return the same value than
<code>checking::empty_lower</code> could return).</p>

<p><code>empty_lower</code> and <code>empty_upper</code> respectively return
the lower and upper bound of the empty interval. There is no requirements for
<code>empty_lower</code> and <code>empty_upper</code> to return the same
value than <code>checking::nan</code>. For example, if the type
<code>T</code> does not have any invalid value, the <code>empty_</code>
functions can return the [1;0] interval.</p>

<p><code>is_nan</code> is used to test if a value of type <code>T</code> is
invalid or not. <code>is_empty</code> tests if the interval formed by the two
arguments is empty or not. Such tests will generally be at the beginning of
each function which involves an argument of type <code>T</code>. If one of
the inputs is declared invalid, the the function will try to produce an
invalid value or an input interval.</p>

<h2>Synopsis</h2>
<pre>namespace boost {
namespace numeric {
namespace interval_lib {

template&lt;class T&gt;
struct checking_base;
template&lt;class T, class Checking = checking_base&lt;T&gt;, class Exception = exception_create_empty&lt;T&gt; &gt;
struct checking_no_empty;
template&lt;class T, class Checking = checking_base&lt;T&gt; &gt;
struct checking_no_nan;
template&lt;class T, class Checking = checking_base&lt;T&gt;, class Exception = exception_invalid_number&lt;T&gt; &gt;
struct checking_catch_nan;

template&lt;class T&gt; struct exception_create_empty { T operator()(); };
template&lt;class T&gt; struct exception_invalid_number { void operator()(); };

} // namespace numeric
} // namespace interval_lib
} // namespace boost</pre>

<h2>Predefined classes</h2>

<p>In order to simplify the customization of the policy, some templates are
already defined in the library.</p>

<p>First of all, there is <code>checking_base</code>. Thanks to the
information provided by <code>std::numeric_limits&lt;T&gt;</code>, this class
is able to generate a base for the policy. If <code>T</code> has quiet NaNs
(as said by <code>numeric_limits::has_quiet_NaN</code>), then the value is
used for <code>nan</code>, <code>empty_lower</code>,
<code>empty_upper</code>; and a basic test is used for <code>is_nan</code>
(it is <code>x!=x</code>). If <code>T</code> does not have quiet NaNs, then
<code>nan</code> is an <code>assert(false)</code>, the empty interval is
[1,0], and <code>is_nan</code> always return <code>false</code>. As for
<code>nan</code>, <code>pos_inf</code> returns
<code>numeric_limits::infinity()</code> if possible, or is an
<code>assert(false</code>) otherwise. <code>neg_inf</code> returns the
opposite. Finally, <code>is_empty(T l,T u)</code> is always defined by
<code>!(l&lt;=u)</code>.</p>

<p>Next comes <code>checking_no_empty</code>. Using it means that each time
an empty interval should be produced (by <code>empty_lower</code> and
<code>empty_upper</code>), the function object given by the
<code>Exception</code> argument of the template is invoked and the value it
returns is propagated. So, if <code>Exception</code> is appropriately defined
(for example it could throw an exception, hence the name of the argument),
you can be sure no empty interval will ever be created. So
<code>is_empty</code> will always return <code>false</code> (since there is
no need to test for an empty interval). And as explained before, in that case
we can also replace <code>nan</code> by an <code>assert(false)</code>; you
will be sure no invalid number will ever be produced. If this template is not
used, it implicitly means that all the functions can produce empty intervals
and they correctly deal with empty interval arguments.</p>

<p>Finally there are <code>checking_no_nan</code> and
<code>checking_catch_nan</code>. The first one expresses the functions of the
library will never get an invalid number as argument. So <code>is_nan</code>
will only return <code>false</code>. The other one means the arguments can be
an invalid number but in that case, <code>is_nan</code> will call the
function object <code>Exception</code> and return <code>false</code>. Indeed,
this template means invalid numbers should never make their way through to
the body of the function. If none of this two templates is used, it
implicitly means that all the functions can get invalid number arguments and
they will correctly deal with them.</p>

<p><code>exception_create_empty</code> throws <code>std::runtime_error</code>
with the message <code>"boost::interval: empty interval created"</code> and
<code>exception_invalid_number</code> throws
<code>std::invalid_argument</code> with the message <code>"boost::interval:
invalid number"</code>.</p>

<h2>Customizing your own checking policy</h2>

<p>In order to define a suitable policy, you need to correctly say what you
expect from your interval class. First of all, are you interested in getting
empty intervals at the end of a calculus? If you do not want to obtain empty
intervals, <code>empty_lower</code> and <code>empty_upper</code> have to fail
when invoked (they can throw an exception, set a flag, etc). However, if no
function is able to produce an empty interval, it is no more necessary to do
the test, so <code>is_empty</code> may always return <code>false</code>. In
this case, a good compiler will do a lot of optimizations.</p>

<p>You could also be interested in getting empty intervals at the end of the
calculus. For example, if you need to transform an array of unsure values (or
intervals) in a new array of intervals, you may not want to stop the
conversion at the first encountered problem. So <code>empty_lower</code> and
<code>empty_upper</code> need to return suitable values in order to define an
empty interval (you can use an upper bound which is not greater or equal than
the lower bound for example); and <code>is_empty</code> must be able to
distinguish empty intervals from the valid intervals.</p>

<p>Another important question is: is it possible that some base numbers
(objects of type <code>T</code>) are invalid? And if it is possible, are they
allowed or not ? If it is not possible, no test is necessary;
<code>is_nan</code> may always return <code>false</code>. In this case too, a
good compiler will do a lot of optimizations. If function arguments can hold
invalid numbers, two cases must be considered according to whether they are
allowed or not. If they are allowed, <code>is_nan</code> just has to test if
they are invalid or not. If they are forbidden, <code>is_nan</code> should
fail (exception, assert, etc.) when invoked on an invalid argument and return
<code>false</code> otherwise. The value returned by <code>nan</code> does not
have any interest since the interval functions are guaranteed not to produce
invalid interval bounds unless the user passes invalid numbers to the
constructors. So you can put an assert inside if you do not trust the
library. :-)</p>

<p>And finally, you need to decide what to do with <code>nan</code> if it has
not already been decided at the beginning, and with <code>pos_inf</code> and
<code>neg_inf</code>. These functions should return a value or start an
exceptional behavior (especially if the base type does not have corresponding
values).</p>

<h2>Some examples</h2>
<ul>
  <li>If you need a checking policy that allows the library to correctly
    manipulate data, even if they contain invalid numbers and empty
    intervals, then <code>checking_base&lt;T&gt;</code> is a possibility.</li>
  <li>If you do not want empty intervals to be created and are not sure all
    the numbers are valid, then <code>checking_catch_nan&lt;T,
    checking_no_empty&lt;T&gt; &gt;</code> can help you.</li>
  <li>If all the numbers will be valid and if no empty interval is supposed
    to be created (or if you do not want them to be created), then you can
    use <code>checking_no_nan&lt;T, checking_no_empty&lt;T&gt; &gt;</code>.
    Please note that if <code>T</code> does not have a way to represent
    invalid numbers, then this policy will behave the same way as
    <code>checking_no_empty&lt;T&gt;</code>. This is the default policy and
    it is also called <code>interval_lib::checking_strict</code>.</li>
  <li>If all numerical data are valid but the algorithm can produce and
    manipulate empty intervals, then <code>checking_no_nan&lt;T&gt;</code>
    should be used.</li>
  <li>Similarly, if invalid data have to be signaled and the algorithm can
    manipulate empty intervals, the <code>checking_catch_nan&lt;T&gt;</code>
    is a solution.</li>
  <li>If you do not mind having undefined results when an empty interval or
    an interval number is produced, your best bet is to create your own
    policy by overloading <code>checking_base</code> and modifying
    <code>is_nan</code> et <code>is_empty</code> in order for them to always
    return <code>false</code>. It is probably the fastest checking policy
    available; however, it suffers from its deficient security.</li>
</ul>
<hr>

<p>Revised: 2004-02-16<br>
Copyright (c) Guillaume Melquiond, Sylvain Pion, Herv Brnnimann, 2002.
Polytechnic University.<br>
Copyright (c) Guillaume Melquiond, 2003-2004.</p>
</body>
</html>