1<html> 2<head> 3<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> 4<title>Testing</title> 5<link rel="stylesheet" href="../../math.css" type="text/css"> 6<meta name="generator" content="DocBook XSL Stylesheets V1.79.1"> 7<link rel="home" href="../../index.html" title="Math Toolkit 2.12.0"> 8<link rel="up" href="../special_tut.html" title="Tutorial: How to Write a New Special Function"> 9<link rel="prev" href="special_tut_impl.html" title="Implementation"> 10<link rel="next" href="../relative_error.html" title="Relative Error"> 11</head> 12<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"> 13<table cellpadding="2" width="100%"><tr> 14<td valign="top"><img alt="Boost C++ Libraries" width="277" height="86" src="../../../../../../boost.png"></td> 15<td align="center"><a href="../../../../../../index.html">Home</a></td> 16<td align="center"><a href="../../../../../../libs/libraries.htm">Libraries</a></td> 17<td align="center"><a href="http://www.boost.org/users/people.html">People</a></td> 18<td align="center"><a href="http://www.boost.org/users/faq.html">FAQ</a></td> 19<td align="center"><a href="../../../../../../more/index.htm">More</a></td> 20</tr></table> 21<hr> 22<div class="spirit-nav"> 23<a accesskey="p" href="special_tut_impl.html"><img src="../../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../special_tut.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="../relative_error.html"><img src="../../../../../../doc/src/images/next.png" alt="Next"></a> 24</div> 25<div class="section"> 26<div class="titlepage"><div><div><h3 class="title"> 27<a name="math_toolkit.special_tut.special_tut_test"></a><a class="link" href="special_tut_test.html" title="Testing">Testing</a> 28</h3></div></div></div> 29<p> 30 We work under the assumption that untested code doesn't work, so some tests 31 for your new special function are in order, we'll divide these up in to 3 32 main categories: 33 </p> 34<h5> 35<a name="math_toolkit.special_tut.special_tut_test.h0"></a> 36 <span class="phrase"><a name="math_toolkit.special_tut.special_tut_test.spot_tests"></a></span><a class="link" href="special_tut_test.html#math_toolkit.special_tut.special_tut_test.spot_tests">Spot Tests</a> 37 </h5> 38<p> 39 Spot tests consist of checking that the expected exception is generated when 40 the inputs are in error (or otherwise generate undefined values), and checking 41 any special values. We can check for expected exceptions with <code class="computeroutput"><span class="identifier">BOOST_CHECK_THROW</span></code>, so for example if it's 42 a domain error for the last parameter to be outside the range <code class="computeroutput"><span class="special">[</span><span class="number">0</span><span class="special">,</span><span class="number">1</span><span class="special">]</span></code> then we 43 might have: 44 </p> 45<pre class="programlisting"><span class="identifier">BOOST_CHECK_THROW</span><span class="special">(</span><span class="identifier">my_special</span><span class="special">(</span><span class="number">0</span><span class="special">,</span> <span class="special">-</span><span class="number">0.1</span><span class="special">),</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">domain_error</span><span class="special">);</span> 46<span class="identifier">BOOST_CHECK_THROW</span><span class="special">(</span><span class="identifier">my_special</span><span class="special">(</span><span class="number">0</span><span class="special">,</span> <span class="number">1.1</span><span class="special">),</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">domain_error</span><span class="special">);</span> 47</pre> 48<p> 49 When the function has known exact values (typically integer values) we can 50 use <code class="computeroutput"><span class="identifier">BOOST_CHECK_EQUAL</span></code>: 51 </p> 52<pre class="programlisting"><span class="identifier">BOOST_CHECK_EQUAL</span><span class="special">(</span><span class="identifier">my_special</span><span class="special">(</span><span class="number">1.0</span><span class="special">,</span> <span class="number">0.0</span><span class="special">),</span> <span class="number">0</span><span class="special">);</span> 53<span class="identifier">BOOST_CHECK_EQUAL</span><span class="special">(</span><span class="identifier">my_special</span><span class="special">(</span><span class="number">1.0</span><span class="special">,</span> <span class="number">1.0</span><span class="special">),</span> <span class="number">1</span><span class="special">);</span> 54</pre> 55<p> 56 When the function has known values which are not exact (from a floating point 57 perspective) then we can use <code class="computeroutput"><span class="identifier">BOOST_CHECK_CLOSE_FRACTION</span></code>: 58 </p> 59<pre class="programlisting"><span class="comment">// Assumes 4 epsilon is as close as we can get to a true value of 2Pi:</span> 60<span class="identifier">BOOST_CHECK_CLOSE_FRACTION</span><span class="special">(</span><span class="identifier">my_special</span><span class="special">(</span><span class="number">0.5</span><span class="special">,</span> <span class="number">0.5</span><span class="special">),</span> <span class="number">2</span> <span class="special">*</span> <span class="identifier">constants</span><span class="special">::</span><span class="identifier">pi</span><span class="special"><</span><span class="keyword">double</span><span class="special">>(),</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">numeric_limits</span><span class="special"><</span><span class="keyword">double</span><span class="special">>::</span><span class="identifier">epsilon</span><span class="special">()</span> <span class="special">*</span> <span class="number">4</span><span class="special">);</span> 61</pre> 62<h5> 63<a name="math_toolkit.special_tut.special_tut_test.h1"></a> 64 <span class="phrase"><a name="math_toolkit.special_tut.special_tut_test.independent_test_values"></a></span><a class="link" href="special_tut_test.html#math_toolkit.special_tut.special_tut_test.independent_test_values">Independent 65 Test Values</a> 66 </h5> 67<p> 68 If the function is implemented by some other known good source (for example 69 Mathematica or it's online versions <a href="http://functions.wolfram.com" target="_top">functions.wolfram.com</a> 70 or <a href="http://www.wolframalpha.com" target="_top">www.wolframalpha.com</a> 71 then it's a good idea to sanity check our implementation by having at least 72 one independently generated value for each code branch our implementation 73 may take. To slot these in nicely with our testing framework it's best to 74 tabulate these like this: 75 </p> 76<pre class="programlisting"><span class="comment">// function values calculated on http://functions.wolfram.com/</span> 77<span class="keyword">static</span> <span class="keyword">const</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">array</span><span class="special"><</span><span class="identifier">boost</span><span class="special">::</span><span class="identifier">array</span><span class="special"><</span><span class="identifier">T</span><span class="special">,</span> <span class="number">3</span><span class="special">>,</span> <span class="number">10</span><span class="special">></span> <span class="identifier">my_special_data</span> <span class="special">=</span> <span class="special">{{</span> 78 <span class="special">{{</span> <span class="identifier">SC_</span><span class="special">(</span><span class="number">0</span><span class="special">),</span> <span class="identifier">SC_</span><span class="special">(</span><span class="number">0</span><span class="special">),</span> <span class="identifier">SC_</span><span class="special">(</span><span class="number">1</span><span class="special">)</span> <span class="special">}},</span> 79 <span class="special">{{</span> <span class="identifier">SC_</span><span class="special">(</span><span class="number">0</span><span class="special">),</span> <span class="identifier">SC_</span><span class="special">(</span><span class="number">1</span><span class="special">),</span> <span class="identifier">SC_</span><span class="special">(</span><span class="number">1.26606587775200833559824462521471753760767031135496220680814</span><span class="special">)</span> <span class="special">}},</span> 80 <span class="comment">/* More values here... */</span> 81<span class="special">}};</span> 82</pre> 83<p> 84 We'll see how to use this table and the meaning of the <code class="computeroutput"><span class="identifier">SC_</span></code> 85 macro later. One important point is to make sure that the input values have 86 exact binary representations: so choose values such as 1.5, 1.25, 1.125 etc. 87 This ensures that if <code class="computeroutput"><span class="identifier">my_special</span></code> 88 is unusually sensitive in one area, that we don't get apparently large errors 89 just because the inputs are 0.5 ulp in error. 90 </p> 91<h5> 92<a name="math_toolkit.special_tut.special_tut_test.h2"></a> 93 <span class="phrase"><a name="math_toolkit.special_tut.special_tut_test.random_test_values"></a></span><a class="link" href="special_tut_test.html#math_toolkit.special_tut.special_tut_test.random_test_values">Random 94 Test Values</a> 95 </h5> 96<p> 97 We can generate a large number of test values to check both for future regressions, 98 and for accumulated rounding or cancellation error in our implementation. 99 Ideally we would use an independent implementation for this (for example 100 my_special may be defined in directly terms of other special functions but 101 not implemented that way for performance or accuracy reasons). Alternatively 102 we may use our own implementation directly, but with any special cases (asymptotic 103 expansions etc) disabled. We have a set of <a class="link" href="../internals/test_data.html" title="Graphing, Profiling, and Generating Test Data for Special Functions">tools</a> 104 to generate test data directly, here's a typical example: 105 </p> 106<pre class="programlisting"><span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">multiprecision</span><span class="special">/</span><span class="identifier">cpp_dec_float</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> 107<span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">math</span><span class="special">/</span><span class="identifier">tools</span><span class="special">/</span><span class="identifier">test_data</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> 108<span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">test</span><span class="special">/</span><span class="identifier">included</span><span class="special">/</span><span class="identifier">prg_exec_monitor</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> 109<span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">fstream</span><span class="special">></span> 110 111<span class="keyword">using</span> <span class="keyword">namespace</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">math</span><span class="special">::</span><span class="identifier">tools</span><span class="special">;</span> 112<span class="keyword">using</span> <span class="keyword">namespace</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">math</span><span class="special">;</span> 113<span class="keyword">using</span> <span class="keyword">namespace</span> <span class="identifier">std</span><span class="special">;</span> 114<span class="keyword">using</span> <span class="keyword">namespace</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">multiprecision</span><span class="special">;</span> 115 116<span class="keyword">template</span> <span class="special"><</span><span class="keyword">class</span> <span class="identifier">T</span><span class="special">></span> 117<span class="identifier">T</span> <span class="identifier">my_special</span><span class="special">(</span><span class="identifier">T</span> <span class="identifier">a</span><span class="special">,</span> <span class="identifier">T</span> <span class="identifier">b</span><span class="special">)</span> 118<span class="special">{</span> 119 <span class="comment">// Implementation of my_special here...</span> 120 <span class="keyword">return</span> <span class="identifier">a</span> <span class="special">+</span> <span class="identifier">b</span><span class="special">;</span> 121<span class="special">}</span> 122 123<span class="keyword">int</span> <span class="identifier">cpp_main</span><span class="special">(</span><span class="keyword">int</span> <span class="identifier">argc</span><span class="special">,</span> <span class="keyword">char</span><span class="special">*</span><span class="identifier">argv</span> <span class="special">[])</span> 124<span class="special">{</span> 125 <span class="comment">//</span> 126 <span class="comment">// We'll use so many digits of precision that any</span> 127 <span class="comment">// calculation errors will still leave us with</span> 128 <span class="comment">// 40-50 good digits. We'll only run this program</span> 129 <span class="comment">// once so it doesn't matter too much how long this takes!</span> 130 <span class="comment">//</span> 131 <span class="keyword">typedef</span> <span class="identifier">number</span><span class="special"><</span><span class="identifier">cpp_dec_float</span><span class="special"><</span><span class="number">500</span><span class="special">></span> <span class="special">></span> <span class="identifier">bignum</span><span class="special">;</span> 132 133 <span class="identifier">parameter_info</span><span class="special"><</span><span class="identifier">bignum</span><span class="special">></span> <span class="identifier">arg1</span><span class="special">,</span> <span class="identifier">arg2</span><span class="special">;</span> 134 <span class="identifier">test_data</span><span class="special"><</span><span class="identifier">bignum</span><span class="special">></span> <span class="identifier">data</span><span class="special">;</span> 135 136 <span class="keyword">bool</span> <span class="identifier">cont</span><span class="special">;</span> 137 <span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="identifier">line</span><span class="special">;</span> 138 139 <span class="keyword">if</span><span class="special">(</span><span class="identifier">argc</span> <span class="special"><</span> <span class="number">1</span><span class="special">)</span> 140 <span class="keyword">return</span> <span class="number">1</span><span class="special">;</span> 141 142 <span class="keyword">do</span><span class="special">{</span> 143 <span class="comment">//</span> 144 <span class="comment">// User interface which prompts for </span> 145 <span class="comment">// range of input parameters:</span> 146 <span class="comment">//</span> 147 <span class="keyword">if</span><span class="special">(</span><span class="number">0</span> <span class="special">==</span> <span class="identifier">get_user_parameter_info</span><span class="special">(</span><span class="identifier">arg1</span><span class="special">,</span> <span class="string">"a"</span><span class="special">))</span> 148 <span class="keyword">return</span> <span class="number">1</span><span class="special">;</span> 149 <span class="keyword">if</span><span class="special">(</span><span class="number">0</span> <span class="special">==</span> <span class="identifier">get_user_parameter_info</span><span class="special">(</span><span class="identifier">arg2</span><span class="special">,</span> <span class="string">"b"</span><span class="special">))</span> 150 <span class="keyword">return</span> <span class="number">1</span><span class="special">;</span> 151 152 <span class="comment">//</span> 153 <span class="comment">// Get a pointer to the function and call</span> 154 <span class="comment">// test_data::insert to actually generate</span> 155 <span class="comment">// the values.</span> 156 <span class="comment">//</span> 157 <span class="identifier">bignum</span> <span class="special">(*</span><span class="identifier">fp</span><span class="special">)(</span><span class="identifier">bignum</span><span class="special">,</span> <span class="identifier">bignum</span><span class="special">)</span> <span class="special">=</span> <span class="special">&</span><span class="identifier">my_special</span><span class="special">;</span> 158 <span class="identifier">data</span><span class="special">.</span><span class="identifier">insert</span><span class="special">(</span><span class="identifier">fp</span><span class="special">,</span> <span class="identifier">arg2</span><span class="special">,</span> <span class="identifier">arg1</span><span class="special">);</span> 159 160 <span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special"><<</span> <span class="string">"Any more data [y/n]?"</span><span class="special">;</span> 161 <span class="identifier">std</span><span class="special">::</span><span class="identifier">getline</span><span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">cin</span><span class="special">,</span> <span class="identifier">line</span><span class="special">);</span> 162 <span class="identifier">boost</span><span class="special">::</span><span class="identifier">algorithm</span><span class="special">::</span><span class="identifier">trim</span><span class="special">(</span><span class="identifier">line</span><span class="special">);</span> 163 <span class="identifier">cont</span> <span class="special">=</span> <span class="special">(</span><span class="identifier">line</span> <span class="special">==</span> <span class="string">"y"</span><span class="special">);</span> 164 <span class="special">}</span><span class="keyword">while</span><span class="special">(</span><span class="identifier">cont</span><span class="special">);</span> 165 <span class="comment">//</span> 166 <span class="comment">// Just need to write the results to a file:</span> 167 <span class="comment">//</span> 168 <span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special"><<</span> <span class="string">"Enter name of test data file [default=my_special.ipp]"</span><span class="special">;</span> 169 <span class="identifier">std</span><span class="special">::</span><span class="identifier">getline</span><span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">cin</span><span class="special">,</span> <span class="identifier">line</span><span class="special">);</span> 170 <span class="identifier">boost</span><span class="special">::</span><span class="identifier">algorithm</span><span class="special">::</span><span class="identifier">trim</span><span class="special">(</span><span class="identifier">line</span><span class="special">);</span> 171 <span class="keyword">if</span><span class="special">(</span><span class="identifier">line</span> <span class="special">==</span> <span class="string">""</span><span class="special">)</span> 172 <span class="identifier">line</span> <span class="special">=</span> <span class="string">"my_special.ipp"</span><span class="special">;</span> 173 <span class="identifier">std</span><span class="special">::</span><span class="identifier">ofstream</span> <span class="identifier">ofs</span><span class="special">(</span><span class="identifier">line</span><span class="special">.</span><span class="identifier">c_str</span><span class="special">());</span> 174 <span class="identifier">line</span><span class="special">.</span><span class="identifier">erase</span><span class="special">(</span><span class="identifier">line</span><span class="special">.</span><span class="identifier">find</span><span class="special">(</span><span class="char">'.'</span><span class="special">));</span> 175 <span class="identifier">ofs</span> <span class="special"><<</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">scientific</span> <span class="special"><<</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">setprecision</span><span class="special">(</span><span class="number">50</span><span class="special">);</span> 176 <span class="identifier">write_code</span><span class="special">(</span><span class="identifier">ofs</span><span class="special">,</span> <span class="identifier">data</span><span class="special">,</span> <span class="identifier">line</span><span class="special">.</span><span class="identifier">c_str</span><span class="special">());</span> 177 178 <span class="keyword">return</span> <span class="number">0</span><span class="special">;</span> 179<span class="special">}</span> 180</pre> 181<p> 182 Typically several sets of data will be generated this way, including random 183 values in some "normal" range, extreme values (very large or very 184 small), and values close to any "interesting" behaviour of the 185 function (singularities etc). 186 </p> 187<h5> 188<a name="math_toolkit.special_tut.special_tut_test.h3"></a> 189 <span class="phrase"><a name="math_toolkit.special_tut.special_tut_test.the_test_file_header"></a></span><a class="link" href="special_tut_test.html#math_toolkit.special_tut.special_tut_test.the_test_file_header">The 190 Test File Header</a> 191 </h5> 192<p> 193 We split the actual test file into 2 distinct parts: a header that contains 194 the testing code as a series of function templates, and the actual .cpp test 195 driver that decides which types are tested, and sets the "expected" 196 error rates for those types. It's done this way because: 197 </p> 198<div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "> 199<li class="listitem"> 200 We want to test with both built in floating point types, and with multiprecision 201 types. However, both compile and runtimes with the latter can be too 202 long for the folks who run the tests to realistically cope with, so it 203 makes sense to split the test into (at least) 2 parts. 204 </li> 205<li class="listitem"> 206 The definition of the SC_ macro used in our tables of data may differ 207 depending on what type we're testing (see below). Again this is largely 208 a matter of managing compile times as large tables of user-defined-types 209 can take a crazy amount of time to compile with some compilers. 210 </li> 211</ul></div> 212<p> 213 The test header contains 2 functions: 214 </p> 215<pre class="programlisting"><span class="keyword">template</span> <span class="special"><</span><span class="keyword">class</span> <span class="identifier">Real</span><span class="special">,</span> <span class="keyword">class</span> <span class="identifier">T</span><span class="special">></span> 216<span class="keyword">void</span> <span class="identifier">do_test</span><span class="special">(</span><span class="keyword">const</span> <span class="identifier">T</span><span class="special">&</span> <span class="identifier">data</span><span class="special">,</span> <span class="keyword">const</span> <span class="keyword">char</span><span class="special">*</span> <span class="identifier">type_name</span><span class="special">,</span> <span class="keyword">const</span> <span class="keyword">char</span><span class="special">*</span> <span class="identifier">test_name</span><span class="special">);</span> 217 218<span class="keyword">template</span> <span class="special"><</span><span class="keyword">class</span> <span class="identifier">T</span><span class="special">></span> 219<span class="keyword">void</span> <span class="identifier">test</span><span class="special">(</span><span class="identifier">T</span><span class="special">,</span> <span class="keyword">const</span> <span class="keyword">char</span><span class="special">*</span> <span class="identifier">type_name</span><span class="special">);</span> 220</pre> 221<p> 222 Before implementing those, we'll include the headers we'll need, and provide 223 a default definition for the SC_ macro: 224 </p> 225<pre class="programlisting"><span class="comment">// A couple of Boost.Test headers in case we need any BOOST_CHECK_* macros:</span> 226<span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">test</span><span class="special">/</span><span class="identifier">unit_test</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> 227<span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">test</span><span class="special">/</span><span class="identifier">tools</span><span class="special">/</span><span class="identifier">floating_point_comparison</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> 228<span class="comment">// Our function to test:</span> 229<span class="preprocessor">#include</span> <span class="special"><</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">my_special</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> 230<span class="comment">// We need boost::array for our test data, plus a few headers from</span> 231<span class="comment">// libs/math/test that contain our testing machinery:</span> 232<span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">array</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> 233<span class="preprocessor">#include</span> <span class="string">"functor.hpp"</span> 234<span class="preprocessor">#include</span> <span class="string">"handle_test_result.hpp"</span> 235<span class="preprocessor">#include</span> <span class="string">"table_type.hpp"</span> 236 237<span class="preprocessor">#ifndef</span> <span class="identifier">SC_</span> 238<span class="preprocessor">#define</span> <span class="identifier">SC_</span><span class="special">(</span><span class="identifier">x</span><span class="special">)</span> <span class="keyword">static_cast</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">table_type</span><span class="special"><</span><span class="identifier">T</span><span class="special">>::</span><span class="identifier">type</span><span class="special">>(</span><span class="identifier">BOOST_JOIN</span><span class="special">(</span><span class="identifier">x</span><span class="special">,</span> <span class="identifier">L</span><span class="special">))</span> 239<span class="preprocessor">#endif</span> 240</pre> 241<p> 242 The easiest function to implement is the "test" function which 243 is what we'll be calling from the test-driver program. It simply includes 244 the files containing the tabular test data and calls <code class="computeroutput"><span class="identifier">do_test</span></code> 245 function for each table, along with a description of what's being tested: 246 </p> 247<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> 248<span class="keyword">void</span> <span class="identifier">test</span><span class="special">(</span><span class="identifier">T</span><span class="special">,</span> <span class="keyword">const</span> <span class="keyword">char</span><span class="special">*</span> <span class="identifier">type_name</span><span class="special">)</span> 249<span class="special">{</span> 250 <span class="comment">//</span> 251 <span class="comment">// The actual test data is rather verbose, so it's in a separate file</span> 252 <span class="comment">//</span> 253 <span class="comment">// The contents are as follows, each row of data contains</span> 254 <span class="comment">// three items, input value a, input value b and my_special(a, b):</span> 255 <span class="comment">//</span> 256<span class="preprocessor"># include</span> <span class="string">"my_special_1.ipp"</span> 257 258 <span class="identifier">do_test</span><span class="special"><</span><span class="identifier">T</span><span class="special">>(</span><span class="identifier">my_special_1</span><span class="special">,</span> <span class="identifier">name</span><span class="special">,</span> <span class="string">"MySpecial Function: Mathematica Values"</span><span class="special">);</span> 259 260<span class="preprocessor"># include</span> <span class="string">"my_special_2.ipp"</span> 261 262 <span class="identifier">do_test</span><span class="special"><</span><span class="identifier">T</span><span class="special">>(</span><span class="identifier">my_special_2</span><span class="special">,</span> <span class="identifier">name</span><span class="special">,</span> <span class="string">"MySpecial Function: Random Values"</span><span class="special">);</span> 263 264<span class="preprocessor"># include</span> <span class="string">"my_special_3.ipp"</span> 265 266 <span class="identifier">do_test</span><span class="special"><</span><span class="identifier">T</span><span class="special">>(</span><span class="identifier">my_special_3</span><span class="special">,</span> <span class="identifier">name</span><span class="special">,</span> <span class="string">"MySpecial Function: Very Small Values"</span><span class="special">);</span> 267<span class="special">}</span> 268</pre> 269<p> 270 The function <code class="computeroutput"><span class="identifier">do_test</span></code> takes 271 each table of data and calculates values for each row of data, along with 272 statistics for max and mean error etc, most of this is handled by some boilerplate 273 code: 274 </p> 275<pre class="programlisting"><span class="keyword">template</span> <span class="special"><</span><span class="keyword">class</span> <span class="identifier">Real</span><span class="special">,</span> <span class="keyword">class</span> <span class="identifier">T</span><span class="special">></span> 276<span class="keyword">void</span> <span class="identifier">do_test</span><span class="special">(</span><span class="keyword">const</span> <span class="identifier">T</span><span class="special">&</span> <span class="identifier">data</span><span class="special">,</span> <span class="keyword">const</span> <span class="keyword">char</span><span class="special">*</span> <span class="identifier">type_name</span><span class="special">,</span> <span class="keyword">const</span> <span class="keyword">char</span><span class="special">*</span> <span class="identifier">test_name</span><span class="special">)</span> 277<span class="special">{</span> 278 <span class="comment">// Get the type of each row and each element in the rows:</span> 279 <span class="keyword">typedef</span> <span class="keyword">typename</span> <span class="identifier">T</span><span class="special">::</span><span class="identifier">value_type</span> <span class="identifier">row_type</span><span class="special">;</span> 280 <span class="keyword">typedef</span> <span class="identifier">Real</span> <span class="identifier">value_type</span><span class="special">;</span> 281 282 <span class="comment">// Get a pointer to our function, we have to use a workaround here</span> 283 <span class="comment">// as some compilers require the template types to be explicitly</span> 284 <span class="comment">// specified, while others don't much like it if it is!</span> 285 <span class="keyword">typedef</span> <span class="identifier">value_type</span> <span class="special">(*</span><span class="identifier">pg</span><span class="special">)(</span><span class="identifier">value_type</span><span class="special">,</span> <span class="identifier">value_type</span><span class="special">);</span> 286<span class="preprocessor">#if</span> <span class="identifier">defined</span><span class="special">(</span><span class="identifier">BOOST_MATH_NO_DEDUCED_FUNCTION_POINTERS</span><span class="special">)</span> 287 <span class="identifier">pg</span> <span class="identifier">funcp</span> <span class="special">=</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">math</span><span class="special">::</span><span class="identifier">my_special</span><span class="special"><</span><span class="identifier">value_type</span><span class="special">,</span> <span class="identifier">value_type</span><span class="special">>;</span> 288<span class="preprocessor">#else</span> 289 <span class="identifier">pg</span> <span class="identifier">funcp</span> <span class="special">=</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">math</span><span class="special">::</span><span class="identifier">my_special</span><span class="special">;</span> 290<span class="preprocessor">#endif</span> 291 292 <span class="comment">// Somewhere to hold our results:</span> 293 <span class="identifier">boost</span><span class="special">::</span><span class="identifier">math</span><span class="special">::</span><span class="identifier">tools</span><span class="special">::</span><span class="identifier">test_result</span><span class="special"><</span><span class="identifier">value_type</span><span class="special">></span> <span class="identifier">result</span><span class="special">;</span> 294 <span class="comment">// And some pretty printing:</span> 295 <span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special"><<</span> <span class="string">"Testing "</span> <span class="special"><<</span> <span class="identifier">test_name</span> <span class="special"><<</span> <span class="string">" with type "</span> <span class="special"><<</span> <span class="identifier">type_name</span> 296 <span class="special"><<</span> <span class="string">"\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n"</span><span class="special">;</span> 297 298 <span class="comment">//</span> 299 <span class="comment">// Test my_special against data:</span> 300 <span class="comment">//</span> 301 <span class="identifier">result</span> <span class="special">=</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">math</span><span class="special">::</span><span class="identifier">tools</span><span class="special">::</span><span class="identifier">test_hetero</span><span class="special"><</span><span class="identifier">Real</span><span class="special">>(</span> 302 <span class="comment">/* First argument is the table */</span> 303 <span class="identifier">data</span><span class="special">,</span> 304 <span class="comment">/* Next comes our function pointer, plus the indexes of it's arguments in the table */</span> 305 <span class="identifier">bind_func</span><span class="special"><</span><span class="identifier">Real</span><span class="special">>(</span><span class="identifier">funcp</span><span class="special">,</span> <span class="number">0</span><span class="special">,</span> <span class="number">1</span><span class="special">),</span> 306 <span class="comment">/* Then the index of the result in the table - potentially we can test several 307 related functions this way, each having the same input arguments, and different 308 output values in different indexes in the table */</span> 309 <span class="identifier">extract_result</span><span class="special"><</span><span class="identifier">Real</span><span class="special">>(</span><span class="number">2</span><span class="special">));</span> 310 <span class="comment">//</span> 311 <span class="comment">// Finish off with some boilerplate to check the results were within the expected errors,</span> 312 <span class="comment">// and pretty print the results:</span> 313 <span class="comment">//</span> 314 <span class="identifier">handle_test_result</span><span class="special">(</span><span class="identifier">result</span><span class="special">,</span> <span class="identifier">data</span><span class="special">[</span><span class="identifier">result</span><span class="special">.</span><span class="identifier">worst</span><span class="special">()],</span> <span class="identifier">result</span><span class="special">.</span><span class="identifier">worst</span><span class="special">(),</span> <span class="identifier">type_name</span><span class="special">,</span> <span class="string">"boost::math::my_special"</span><span class="special">,</span> <span class="identifier">test_name</span><span class="special">);</span> 315<span class="special">}</span> 316</pre> 317<p> 318 Now we just need to write the test driver program, at it's most basic it 319 looks something like this: 320 </p> 321<pre class="programlisting"><span class="preprocessor">#include</span> <span class="special"><</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">math_fwd</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> 322<span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">math</span><span class="special">/</span><span class="identifier">tools</span><span class="special">/</span><span class="identifier">test</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> 323<span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">math</span><span class="special">/</span><span class="identifier">tools</span><span class="special">/</span><span class="identifier">stats</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> 324<span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">type_traits</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> 325<span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">array</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> 326<span class="preprocessor">#include</span> <span class="string">"functor.hpp"</span> 327 328<span class="preprocessor">#include</span> <span class="string">"handle_test_result.hpp"</span> 329<span class="preprocessor">#include</span> <span class="string">"test_my_special.hpp"</span> 330 331<span class="identifier">BOOST_AUTO_TEST_CASE</span><span class="special">(</span> <span class="identifier">test_main</span> <span class="special">)</span> 332<span class="special">{</span> 333 <span class="comment">//</span> 334 <span class="comment">// Test each floating point type, plus real_concept.</span> 335 <span class="comment">// We specify the name of each type by hand as typeid(T).name()</span> 336 <span class="comment">// often gives an unreadable mangled name.</span> 337 <span class="comment">//</span> 338 <span class="identifier">test</span><span class="special">(</span><span class="number">0.1F</span><span class="special">,</span> <span class="string">"float"</span><span class="special">);</span> 339 <span class="identifier">test</span><span class="special">(</span><span class="number">0.1</span><span class="special">,</span> <span class="string">"double"</span><span class="special">);</span> 340 <span class="comment">//</span> 341 <span class="comment">// Testing of long double and real_concept is protected</span> 342 <span class="comment">// by some logic to disable these for unsupported</span> 343 <span class="comment">// or problem compilers.</span> 344 <span class="comment">//</span> 345<span class="preprocessor">#ifndef</span> <span class="identifier">BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS</span> 346 <span class="identifier">test</span><span class="special">(</span><span class="number">0.1L</span><span class="special">,</span> <span class="string">"long double"</span><span class="special">);</span> 347<span class="preprocessor">#ifndef</span> <span class="identifier">BOOST_MATH_NO_REAL_CONCEPT_TESTS</span> 348<span class="preprocessor">#if</span> <span class="special">!</span><span class="identifier">BOOST_WORKAROUND</span><span class="special">(</span><span class="identifier">__BORLANDC__</span><span class="special">,</span> <span class="identifier">BOOST_TESTED_AT</span><span class="special">(</span><span class="number">0x582</span><span class="special">))</span> 349 <span class="identifier">test</span><span class="special">(</span><span class="identifier">boost</span><span class="special">::</span><span class="identifier">math</span><span class="special">::</span><span class="identifier">concepts</span><span class="special">::</span><span class="identifier">real_concept</span><span class="special">(</span><span class="number">0.1</span><span class="special">),</span> <span class="string">"real_concept"</span><span class="special">);</span> 350<span class="preprocessor">#endif</span> 351<span class="preprocessor">#endif</span> 352<span class="preprocessor">#else</span> 353 <span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special"><<</span> <span class="string">"<note>The long double tests have been disabled on this platform "</span> 354 <span class="string">"either because the long double overloads of the usual math functions are "</span> 355 <span class="string">"not available at all, or because they are too inaccurate for these tests "</span> 356 <span class="string">"to pass.</note>"</span> <span class="special"><<</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span><span class="special">;</span> 357<span class="preprocessor">#endif</span> 358<span class="special">}</span> 359</pre> 360<p> 361 That's almost all there is too it - except that if the above program is run 362 it's very likely that all the tests will fail as the default maximum allowable 363 error is 1 epsilon. So we'll define a function (don't forget to call it from 364 the start of the <code class="computeroutput"><span class="identifier">test_main</span></code> 365 above) to up the limits to something sensible, based both on the function 366 we're calling and on the particular tests plus the platform and compiler: 367 </p> 368<pre class="programlisting"><span class="keyword">void</span> <span class="identifier">expected_results</span><span class="special">()</span> 369<span class="special">{</span> 370 <span class="comment">//</span> 371 <span class="comment">// Define the max and mean errors expected for</span> 372 <span class="comment">// various compilers and platforms.</span> 373 <span class="comment">//</span> 374 <span class="keyword">const</span> <span class="keyword">char</span><span class="special">*</span> <span class="identifier">largest_type</span><span class="special">;</span> 375<span class="preprocessor">#ifndef</span> <span class="identifier">BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS</span> 376 <span class="keyword">if</span><span class="special">(</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="identifier">digits</span><span class="special"><</span><span class="keyword">double</span><span class="special">,</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="identifier">policy</span><span class="special"><></span> <span class="special">>()</span> <span class="special">==</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="identifier">digits</span><span class="special"><</span><span class="keyword">long</span> <span class="keyword">double</span><span class="special">,</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="identifier">policy</span><span class="special"><></span> <span class="special">>())</span> 377 <span class="special">{</span> 378 <span class="identifier">largest_type</span> <span class="special">=</span> <span class="string">"(long\\s+)?double|real_concept"</span><span class="special">;</span> 379 <span class="special">}</span> 380 <span class="keyword">else</span> 381 <span class="special">{</span> 382 <span class="identifier">largest_type</span> <span class="special">=</span> <span class="string">"long double|real_concept"</span><span class="special">;</span> 383 <span class="special">}</span> 384<span class="preprocessor">#else</span> 385 <span class="identifier">largest_type</span> <span class="special">=</span> <span class="string">"(long\\s+)?double"</span><span class="special">;</span> 386<span class="preprocessor">#endif</span> 387 <span class="comment">//</span> 388 <span class="comment">// We call add_expected_result for each error rate we wish to adjust, these tell</span> 389 <span class="comment">// handle_test_result what level of error is acceptable. We can have as many calls</span> 390 <span class="comment">// to add_expected_result as we need, each one establishes a rule for acceptable error</span> 391 <span class="comment">// with rules set first given preference.</span> 392 <span class="comment">//</span> 393 <span class="identifier">add_expected_result</span><span class="special">(</span> 394 <span class="comment">/* First argument is a regular expression to match against the name of the compiler 395 set in BOOST_COMPILER */</span> 396 <span class="string">".*"</span><span class="special">,</span> 397 <span class="comment">/* Second argument is a regular expression to match against the name of the 398 C++ standard library as set in BOOST_STDLIB */</span> 399 <span class="string">".*"</span><span class="special">,</span> 400 <span class="comment">/* Third argument is a regular expression to match against the name of the 401 platform as set in BOOST_PLATFORM */</span> 402 <span class="string">".*"</span><span class="special">,</span> 403 <span class="comment">/* Forth argument is the name of the type being tested, normally we will 404 only need to up the acceptable error rate for the widest floating 405 point type being tested */</span> 406 <span class="identifier">largest_real</span><span class="special">,</span> 407 <span class="comment">/* Fifth argument is a regular expression to match against 408 the name of the group of data being tested */</span> 409 <span class="string">"MySpecial Function:.*Small.*"</span><span class="special">,</span> 410 <span class="comment">/* Sixth argument is a regular expression to match against the name 411 of the function being tested */</span> 412 <span class="string">"boost::math::my_special"</span><span class="special">,</span> 413 <span class="comment">/* Seventh argument is the maximum allowable error expressed in units 414 of machine epsilon passed as a long integer value */</span> 415 <span class="number">50</span><span class="special">,</span> 416 <span class="comment">/* Eighth argument is the maximum allowable mean error expressed in units 417 of machine epsilon passed as a long integer value */</span> 418 <span class="number">20</span><span class="special">);</span> 419<span class="special">}</span> 420</pre> 421<h5> 422<a name="math_toolkit.special_tut.special_tut_test.h4"></a> 423 <span class="phrase"><a name="math_toolkit.special_tut.special_tut_test.testing_multiprecision_types"></a></span><a class="link" href="special_tut_test.html#math_toolkit.special_tut.special_tut_test.testing_multiprecision_types">Testing 424 Multiprecision Types</a> 425 </h5> 426<p> 427 Testing of multiprecision types is handled by the test drivers in libs/multiprecision/test/math, 428 please refer to these for examples. Note that these tests are run only occasionally 429 as they take a lot of CPU cycles to build and run. 430 </p> 431<h5> 432<a name="math_toolkit.special_tut.special_tut_test.h5"></a> 433 <span class="phrase"><a name="math_toolkit.special_tut.special_tut_test.improving_compile_times"></a></span><a class="link" href="special_tut_test.html#math_toolkit.special_tut.special_tut_test.improving_compile_times">Improving 434 Compile Times</a> 435 </h5> 436<p> 437 As noted above, these test programs can take a while to build as we're instantiating 438 a lot of templates for several different types, and our test runners are 439 already stretched to the limit, and probably using outdated "spare" 440 hardware. There are two things we can do to speed things up: 441 </p> 442<div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "> 443<li class="listitem"> 444 Use a precompiled header. 445 </li> 446<li class="listitem"> 447 Use separate compilation of our special function templates. 448 </li> 449</ul></div> 450<p> 451 We can make these changes by changing the list of includes from: 452 </p> 453<pre class="programlisting"><span class="preprocessor">#include</span> <span class="special"><</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">math_fwd</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> 454<span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">math</span><span class="special">/</span><span class="identifier">tools</span><span class="special">/</span><span class="identifier">test</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> 455<span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">math</span><span class="special">/</span><span class="identifier">tools</span><span class="special">/</span><span class="identifier">stats</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> 456<span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">type_traits</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> 457<span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">array</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> 458<span class="preprocessor">#include</span> <span class="string">"functor.hpp"</span> 459 460<span class="preprocessor">#include</span> <span class="string">"handle_test_result.hpp"</span> 461</pre> 462<p> 463 To just: 464 </p> 465<pre class="programlisting"><span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">pch_light</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> 466</pre> 467<p> 468 And changing 469 </p> 470<pre class="programlisting"><span class="preprocessor">#include</span> <span class="special"><</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">my_special</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> 471</pre> 472<p> 473 To: 474 </p> 475<pre class="programlisting"><span class="preprocessor">#include</span> <span class="special"><</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">math_fwd</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span> 476</pre> 477<p> 478 The Jamfile target that builds the test program will need the targets 479 </p> 480<pre class="programlisting"><span class="identifier">test_instances</span><span class="comment">//test_instances pch_light</span> 481</pre> 482<p> 483 adding to it's list of source dependencies (see the Jamfile for examples). 484 </p> 485<p> 486 Finally the project in libs/math/test/test_instances will need modifying 487 to instantiate function <code class="computeroutput"><span class="identifier">my_special</span></code>. 488 </p> 489<p> 490 These changes should be made last, when <code class="computeroutput"><span class="identifier">my_special</span></code> 491 is stable and the code is in Trunk. 492 </p> 493<h5> 494<a name="math_toolkit.special_tut.special_tut_test.h6"></a> 495 <span class="phrase"><a name="math_toolkit.special_tut.special_tut_test.concept_checks"></a></span><a class="link" href="special_tut_test.html#math_toolkit.special_tut.special_tut_test.concept_checks">Concept 496 Checks</a> 497 </h5> 498<p> 499 Our concept checks verify that your function's implementation makes no assumptions 500 that aren't required by our <a class="link" href="../real_concepts.html" title="Conceptual Requirements for Real Number Types">Real 501 number conceptual requirements</a>. They also check for various common 502 bugs and programming traps that we've fallen into over time. To add your 503 function to these tests, edit libs/math/test/compile_test/instantiate.hpp 504 to add calls to your function: there are 7 calls to each function, each with 505 a different purpose. Search for something like "ibeta" or "gamm_p" 506 and follow their examples. 507 </p> 508</div> 509<table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr> 510<td align="left"></td> 511<td align="right"><div class="copyright-footer">Copyright © 2006-2019 Nikhar 512 Agrawal, Anton Bikineev, Paul A. Bristow, Marco Guazzone, Christopher Kormanyos, 513 Hubert Holin, Bruno Lalande, John Maddock, Jeremy Murphy, Matthew Pulver, Johan 514 Råde, Gautam Sewani, Benjamin Sobotta, Nicholas Thompson, Thijs van den Berg, 515 Daryle Walker and Xiaogang Zhang<p> 516 Distributed under the Boost Software License, Version 1.0. (See accompanying 517 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>) 518 </p> 519</div></td> 520</tr></table> 521<hr> 522<div class="spirit-nav"> 523<a accesskey="p" href="special_tut_impl.html"><img src="../../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../special_tut.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="../relative_error.html"><img src="../../../../../../doc/src/images/next.png" alt="Next"></a> 524</div> 525</body> 526</html> 527