rounding.htm 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632
  1. <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
  2. "http://www.w3.org/TR/html4/loose.dtd">
  3. <html>
  4. <head>
  5. <meta http-equiv="Content-Language" content="en-us">
  6. <meta http-equiv="Content-Type" content="text/html; charset=us-ascii">
  7. <link rel="stylesheet" type="text/css" href="../../../../boost.css">
  8. <title>Rounding Policies</title>
  9. </head>
  10. <body lang="en">
  11. <h1>Rounding Policies</h1>
  12. <p>In order to be as general as possible, the library uses a class to
  13. compute all the necessary functions rounded upward or downward. This class
  14. is the first parameter of <code>policies</code>, it is also the type named
  15. <code>rounding</code> in the policy definition of
  16. <code>interval</code>.</p>
  17. <p>By default, it is <code>interval_lib::rounded_math&lt;T&gt;</code>. The
  18. class <code>interval_lib::rounded_math</code> is already specialized for
  19. the standard floating types (<code>float</code> , <code>double</code> and
  20. <code>long double</code>). So if the base type of your intervals is not one
  21. of these, a good solution would probably be to provide a specialization of
  22. this class. But if the default specialization of
  23. <code>rounded_math&lt;T&gt;</code> for <code>float</code>,
  24. <code>double</code>, or <code>long double</code> is not what you seek, or
  25. you do not want to specialize
  26. <code>interval_lib::rounded_math&lt;T&gt;</code> (say because you prefer to
  27. work in your own namespace) you can also define your own rounding policy
  28. and pass it directly to <code>interval_lib::policies</code>.</p>
  29. <h2>Requirements</h2>
  30. <p>Here comes what the class is supposed to provide. The domains are
  31. written next to their respective functions (as you can see, the functions
  32. do not have to worry about invalid values, but they have to handle infinite
  33. arguments).</p>
  34. <pre>
  35. /* Rounding requirements */
  36. struct rounding {
  37. // default constructor, destructor
  38. rounding();
  39. ~rounding();
  40. // mathematical operations
  41. T add_down(T, T); // [-&infin;;+&infin;][-&infin;;+&infin;]
  42. T add_up (T, T); // [-&infin;;+&infin;][-&infin;;+&infin;]
  43. T sub_down(T, T); // [-&infin;;+&infin;][-&infin;;+&infin;]
  44. T sub_up (T, T); // [-&infin;;+&infin;][-&infin;;+&infin;]
  45. T mul_down(T, T); // [-&infin;;+&infin;][-&infin;;+&infin;]
  46. T mul_up (T, T); // [-&infin;;+&infin;][-&infin;;+&infin;]
  47. T div_down(T, T); // [-&infin;;+&infin;]([-&infin;;+&infin;]-{0})
  48. T div_up (T, T); // [-&infin;;+&infin;]([-&infin;;+&infin;]-{0})
  49. T sqrt_down(T); // ]0;+&infin;]
  50. T sqrt_up (T); // ]0;+&infin;]
  51. T exp_down(T); // [-&infin;;+&infin;]
  52. T exp_up (T); // [-&infin;;+&infin;]
  53. T log_down(T); // ]0;+&infin;]
  54. T log_up (T); // ]0;+&infin;]
  55. T cos_down(T); // [0;2&pi;]
  56. T cos_up (T); // [0;2&pi;]
  57. T tan_down(T); // ]-&pi;/2;&pi;/2[
  58. T tan_up (T); // ]-&pi;/2;&pi;/2[
  59. T asin_down(T); // [-1;1]
  60. T asin_up (T); // [-1;1]
  61. T acos_down(T); // [-1;1]
  62. T acos_up (T); // [-1;1]
  63. T atan_down(T); // [-&infin;;+&infin;]
  64. T atan_up (T); // [-&infin;;+&infin;]
  65. T sinh_down(T); // [-&infin;;+&infin;]
  66. T sinh_up (T); // [-&infin;;+&infin;]
  67. T cosh_down(T); // [-&infin;;+&infin;]
  68. T cosh_up (T); // [-&infin;;+&infin;]
  69. T tanh_down(T); // [-&infin;;+&infin;]
  70. T tanh_up (T); // [-&infin;;+&infin;]
  71. T asinh_down(T); // [-&infin;;+&infin;]
  72. T asinh_up (T); // [-&infin;;+&infin;]
  73. T acosh_down(T); // [1;+&infin;]
  74. T acosh_up (T); // [1;+&infin;]
  75. T atanh_down(T); // [-1;1]
  76. T atanh_up (T); // [-1;1]
  77. T median(T, T); // [-&infin;;+&infin;][-&infin;;+&infin;]
  78. T int_down(T); // [-&infin;;+&infin;]
  79. T int_up (T); // [-&infin;;+&infin;]
  80. // conversion functions
  81. T conv_down(U);
  82. T conv_up (U);
  83. // unprotected rounding class
  84. typedef ... unprotected_rounding;
  85. };
  86. </pre>
  87. <p>The constructor and destructor of the rounding class have a very
  88. important semantic requirement: they are responsible for setting and
  89. resetting the rounding modes of the computation on T. For instance, if T is
  90. a standard floating point type and floating point computation is performed
  91. according to the Standard IEEE 754, the constructor can save the current
  92. rounding state, each <code>_up</code> (resp. <code>_down</code>) function
  93. will round up (resp. down), and the destructor will restore the saved
  94. rounding state. Indeed this is the behavior of the default rounding
  95. policy.</p>
  96. <p>The meaning of all the mathematical functions up until
  97. <code>atanh_up</code> is clear: each function returns number representable
  98. in the type <code>T</code> which is a lower bound (for <code>_down</code>)
  99. or upper bound (for <code>_up</code>) on the true mathematical result of
  100. the corresponding function. The function <code>median</code> computes the
  101. average of its two arguments rounded to its nearest representable number.
  102. The functions <code>int_down</code> and <code>int_up</code> compute the
  103. nearest integer smaller or bigger than their argument. Finally,
  104. <code>conv_down</code> and <code>conv_up</code> are responsible of the
  105. conversions of values of other types to the base number type: the first one
  106. must round down the value and the second one must round it up.</p>
  107. <p>The type <code>unprotected_rounding</code> allows to remove all
  108. controls. For reasons why one might to do this, see the <a href=
  109. "#Protection">protection</a> paragraph below.</p>
  110. <h2>Overview of the provided classes</h2>
  111. <p>A lot of classes are provided. The classes are organized by level. At
  112. the bottom is the class <code>rounding_control</code>. At the next level
  113. come <code>rounded_arith_exact</code>, <code>rounded_arith_std</code> and
  114. <code>rounded_arith_opp</code>. Then there are
  115. <code>rounded_transc_dummy</code>, <code>rounded_transc_exact</code>,
  116. <code>rounded_transc_std</code> and <code>rounded_transc_opp</code>. And
  117. finally are <code>save_state</code> and <code>save_state_nothing</code>.
  118. Each of these classes provide a set of members that are required by the
  119. classes of the next level. For example, a <code>rounded_transc_...</code>
  120. class needs the members of a <code>rounded_arith_...</code> class.</p>
  121. <p>When they exist in two versions <code>_std</code> and <code>_opp</code>,
  122. the first one does switch the rounding mode each time, and the second one
  123. tries to keep it oriented toward plus infinity. The main purpose of the
  124. <code>_opp</code> version is to speed up the computations through the use
  125. of the "opposite trick" (see the <a href="#perf">performance notes</a>).
  126. This version requires the rounding mode to be upward before entering any
  127. computation functions of the class. It guarantees that the rounding mode
  128. will still be upward at the exit of the functions.</p>
  129. <p>Please note that it is really a very bad idea to mix the
  130. <code>_opp</code> version with the <code>_std</code> since they do not have
  131. compatible properties.</p>
  132. <p>There is a third version named <code>_exact</code> which computes the
  133. functions without changing the rounding mode. It is an "exact" version
  134. because it is intended for a base type that produces exact results.</p>
  135. <p>The last version is the <code>_dummy</code> version. It does not do any
  136. computations but still produces compatible results.</p>
  137. <p>Please note that it is possible to use the "exact" version for an
  138. inexact base type, e.g. <code>float</code> or <code>double</code>. In that
  139. case, the inclusion property is no longer guaranteed, but this can be
  140. useful to speed up the computation when the inclusion property is not
  141. desired strictly. For instance, in computer graphics, a small error due to
  142. floating-point roundoff is acceptable as long as an approximate version of
  143. the inclusion property holds.</p>
  144. <p>Here comes what each class defines. Later, when they will be described
  145. more thoroughly, these members will not be repeated. Please come back here
  146. in order to see them. Inheritance is also used to avoid repetitions.</p>
  147. <pre>
  148. template &lt;class T&gt;
  149. struct rounding_control
  150. {
  151. typedef ... rounding_mode;
  152. void set_rounding_mode(rounding_mode);
  153. void get_rounding_mode(rounding_mode&amp;);
  154. void downward ();
  155. void upward ();
  156. void to_nearest();
  157. T to_int(T);
  158. T force_rounding(T);
  159. };
  160. template &lt;class T, class Rounding&gt;
  161. struct rounded_arith_... : Rounding
  162. {
  163. void init();
  164. T add_down(T, T);
  165. T add_up (T, T);
  166. T sub_down(T, T);
  167. T sub_up (T, T);
  168. T mul_down(T, T);
  169. T mul_up (T, T);
  170. T div_down(T, T);
  171. T div_up (T, T);
  172. T sqrt_down(T);
  173. T sqrt_up (T);
  174. T median(T, T);
  175. T int_down(T);
  176. T int_up (T);
  177. };
  178. template &lt;class T, class Rounding&gt;
  179. struct rounded_transc_... : Rounding
  180. {
  181. T exp_down(T);
  182. T exp_up (T);
  183. T log_down(T);
  184. T log_up (T);
  185. T cos_down(T);
  186. T cos_up (T);
  187. T tan_down(T);
  188. T tan_up (T);
  189. T asin_down(T);
  190. T asin_up (T);
  191. T acos_down(T);
  192. T acos_up (T);
  193. T atan_down(T);
  194. T atan_up (T);
  195. T sinh_down(T);
  196. T sinh_up (T);
  197. T cosh_down(T);
  198. T cosh_up (T);
  199. T tanh_down(T);
  200. T tanh_up (T);
  201. T asinh_down(T);
  202. T asinh_up (T);
  203. T acosh_down(T);
  204. T acosh_up (T);
  205. T atanh_down(T);
  206. T atanh_up (T);
  207. };
  208. template &lt;class Rounding&gt;
  209. struct save_state_... : Rounding
  210. {
  211. save_state_...();
  212. ~save_state_...();
  213. typedef ... unprotected_rounding;
  214. };
  215. </pre>
  216. <h2>Synopsis</h2>
  217. <pre>
  218. namespace boost {
  219. namespace numeric {
  220. namespace interval_lib {
  221. <span style="color: #FF0000">/* basic rounding control */</span>
  222. template &lt;class T&gt; struct rounding_control;
  223. <span style="color: #FF0000">/* arithmetic functions rounding */</span>
  224. template &lt;class T, class Rounding = rounding_control&lt;T&gt; &gt; struct rounded_arith_exact;
  225. template &lt;class T, class Rounding = rounding_control&lt;T&gt; &gt; struct rounded_arith_std;
  226. template &lt;class T, class Rounding = rounding_control&lt;T&gt; &gt; struct rounded_arith_opp;
  227. <span style="color: #FF0000">/* transcendental functions rounding */</span>
  228. template &lt;class T, class Rounding&gt; struct rounded_transc_dummy;
  229. template &lt;class T, class Rounding = rounded_arith_exact&lt;T&gt; &gt; struct rounded_transc_exact;
  230. template &lt;class T, class Rounding = rounded_arith_std&lt;T&gt; &gt; struct rounded_transc_std;
  231. template &lt;class T, class Rounding = rounded_arith_opp&lt;T&gt; &gt; struct rounded_transc_opp;
  232. <span style="color: #FF0000">/* rounding-state-saving classes */</span>
  233. template &lt;class Rounding&gt; struct save_state;
  234. template &lt;class Rounding&gt; struct save_state_nothing;
  235. <span style="color: #FF0000">/* default policy for type T */</span>
  236. template &lt;class T&gt; struct rounded_math;
  237. template &lt;&gt; struct rounded_math&lt;float&gt;;
  238. template &lt;&gt; struct rounded_math&lt;double&gt;;
  239. <span style=
  240. "color: #FF0000">/* some metaprogramming to convert a protected to unprotected rounding */</span>
  241. template &lt;class I&gt; struct unprotect;
  242. } // namespace interval_lib
  243. } // namespace numeric
  244. } // namespace boost
  245. </pre>
  246. <h2>Description of the provided classes</h2>
  247. <p>We now describe each class in the order they appear in the definition of
  248. a rounding policy (this outermost-to-innermost order is the reverse order
  249. from the synopsis).</p>
  250. <h3 id="Protection">Protection control</h3>
  251. <p>Protection refers to the fact that the interval operations will be
  252. surrounded by rounding mode controls. Unprotecting a class means to remove
  253. all the rounding controls. Each rounding policy provides a type
  254. <code>unprotected_rounding</code>. The required type
  255. <code>unprotected_rounding</code> gives another rounding class that enables
  256. to work when nested inside rounding. For example, the first three lines
  257. below should all produce the same result (because the first operation is
  258. the rounding constructor, and the last is its destructor, which take care
  259. of setting the rounding modes); and the last line is allowed to have an
  260. undefined behavior (since no rounding constructor or destructor is ever
  261. called).</p>
  262. <pre>
  263. T c; { rounding rnd; c = rnd.add_down(a, b); }
  264. T c; { rounding rnd1; { rounding rnd2; c = rnd2.add_down(a, b); } }
  265. T c; { rounding rnd1; { rounding::unprotected_rounding rnd2; c = rnd2.add_down(a, b); } }
  266. T d; { rounding::unprotected_rounding rnd; d = rnd.add_down(a, b); }
  267. </pre>
  268. <p>Naturally <code>rounding::unprotected_rounding</code> may simply be
  269. <code>rounding</code> itself. But it can improve performance if it is a
  270. simplified version with empty constructor and destructor. In order to avoid
  271. undefined behaviors, in the library, an object of type
  272. <code>rounding::unprotected_rounding</code> is guaranteed to be created
  273. only when an object of type <code>rounding</code> is already alive. See the
  274. <a href="#perf">performance notes</a> for some additional details.</p>
  275. <p>The support library defines a metaprogramming class template
  276. <code>unprotect</code> which takes an interval type <code>I</code> and
  277. returns an interval type <code>unprotect&lt;I&gt;::type</code> where the
  278. rounding policy has been unprotected. Some information about the types:
  279. <code>interval&lt;T, interval_lib::policies&lt;Rounding, _&gt;
  280. &gt;::traits_type::rounding</code> <b>is</b> the same type as
  281. <code>Rounding</code>, and <code>unprotect&lt;interval&lt;T,
  282. interval_lib::policies&lt;Rounding, _&gt; &gt; &gt;::type</code> <b>is</b>
  283. the same type as <code>interval&lt;T,
  284. interval_lib::policies&lt;Rounding::unprotected, _&gt; &gt;</code>.</p>
  285. <h3>State saving</h3>
  286. <p>First comes <code>save_state</code>. This class is responsible for
  287. saving the current rounding mode and calling init in its constructor, and
  288. for restoring the saved rounding mode in its destructor. This class also
  289. defines the <code>unprotected_rounding</code> type.</p>
  290. <p>If the rounding mode does not require any state-saving or
  291. initialization, <code>save_state_nothing</code> can be used instead of
  292. <code>save_state</code>.</p>
  293. <h3>Transcendental functions</h3>
  294. <p>The classes <code>rounded_transc_exact</code>,
  295. <code>rounded_transc_std</code> and <code>rounded_transc_opp</code> expect
  296. the std namespace to provide the functions exp log cos tan acos asin atan
  297. cosh sinh tanh acosh asinh atanh. For the <code>_std</code> and
  298. <code>_opp</code> versions, all these functions should respect the current
  299. rounding mode fixed by a call to downward or upward.</p>
  300. <p><strong>Please note:</strong> Unfortunately, the latter is rarely the
  301. case. It is the reason why a class <code>rounded_transc_dummy</code> is
  302. provided which does not depend on the functions from the std namespace.
  303. There is no magic, however. The functions of
  304. <code>rounded_transc_dummy</code> do not compute anything. They only return
  305. valid values. For example, <code>cos_down</code> always returns -1. In this
  306. way, we do verify the inclusion property for the default implementation,
  307. even if this has strictly no value for the user. In order to have useful
  308. values, another policy should be used explicitely, which will most likely
  309. lead to a violation of the inclusion property. In this way, we ensure that
  310. the violation is clearly pointed out to the user who then knows what he
  311. stands against. This class could have been used as the default
  312. transcendental rounding class, but it was decided it would be better for
  313. the compilation to fail due to missing declarations rather than succeed
  314. thanks to valid but unusable functions.</p>
  315. <h3>Basic arithmetic functions</h3>
  316. <p>The classes <code>rounded_arith_std</code> and
  317. <code>rounded_arith_opp</code> expect the operators + - * / and the
  318. function <code>std::sqrt</code> to respect the current rounding mode.</p>
  319. <p>The class <code>rounded_arith_exact</code> requires
  320. <code>std::floor</code> and <code>std::ceil</code> to be defined since it
  321. can not rely on <code>to_int</code>.</p>
  322. <h3>Rounding control</h3>
  323. <p>The functions defined by each of the previous classes did not need any
  324. explanation. For example, the behavior of <code>add_down</code> is to
  325. compute the sum of two numbers rounded downward. For
  326. <code>rounding_control</code>, the situation is a bit more complex.</p>
  327. <p>The basic function is <code>force_rounding</code> which returns its
  328. argument correctly rounded accordingly to the current rounding mode if it
  329. was not already the case. This function is necessary to handle delayed
  330. rounding. Indeed, depending on the way the computations are done, the
  331. intermediate results may be internally stored in a more precise format and
  332. it can lead to a wrong rounding. So the function enforces the rounding.
  333. <a href="#extreg">Here</a> is an example of what happens when the rounding
  334. is not enforced.</p>
  335. <p>The function <code>get_rounding_mode</code> returns the current rounding
  336. mode, <code>set_rounding_mode</code> sets the rounding mode back to a
  337. previous value returned by <code>get_rounding_mode</code>.
  338. <code>downward</code>, <code>upward</code> and <code>to_nearest</code> sets
  339. the rounding mode in one of the three directions. This rounding mode should
  340. be global to all the functions that use the type <code>T</code>. For
  341. example, after a call to <code>downward</code>,
  342. <code>force_rounding(x+y)</code> is expected to return the sum rounded
  343. toward -&infin;.</p>
  344. <p>The function <code>to_int</code> computes the nearest integer
  345. accordingly to the current rounding mode.</p>
  346. <p>The non-specialized version of <code>rounding_control</code> does not do
  347. anything. The functions for the rounding mode are empty, and
  348. <code>to_int</code> and <code>force_rounding</code> are identity functions.
  349. The <code>pi_</code> constant functions return suitable integers (for
  350. example, <code>pi_up</code> returns <code>T(4)</code>).</p>
  351. <p>The class template <code>rounding_control</code> is specialized for
  352. <code>float</code>, <code>double</code> and <code>long double</code> in
  353. order to best use the floating point unit of the computer.</p>
  354. <h2>Template class <tt>rounded_math</tt></h2>
  355. <p>The default policy (aka <code>rounded_math&lt;T&gt;</code>) is simply
  356. defined as:</p>
  357. <pre>
  358. template &lt;class T&gt; struct rounded_math&lt;T&gt; : save_state_nothing&lt;rounded_arith_exact&lt;T&gt; &gt; {};
  359. </pre>
  360. <p>and the specializations for <code>float</code>, <code>double</code> and
  361. <code>long double</code> use <code>rounded_arith_opp</code>, as in:</p>
  362. <pre>
  363. template &lt;&gt; struct rounded_math&lt;float&gt; : save_state&lt;rounded_arith_opp&lt;float&gt; &gt; {};
  364. template &lt;&gt; struct rounded_math&lt;double&gt; : save_state&lt;rounded_arith_opp&lt;double&gt; &gt; {};
  365. template &lt;&gt; struct rounded_math&lt;long double&gt; : save_state&lt;rounded_arith_opp&lt;long double&gt; &gt; {};
  366. </pre>
  367. <h2 id="perf">Performance Issues</h2>
  368. <p>This paragraph deals mostly with the performance of the library with
  369. intervals using the floating-point unit (FPU) of the computer. Let's
  370. consider the sum of [<i>a</i>,<i>b</i>] and [<i>c</i>,<i>d</i>] as an
  371. example. The result is [<code>down</code>(<i>a</i>+<i>c</i>),
  372. <code>up</code>(<i>b</i>+<i>d</i>)], where <code>down</code> and
  373. <code>up</code> indicate the rounding mode needed.</p>
  374. <h3>Rounding Mode Switch</h3>
  375. <p>If the FPU is able to use a different rounding mode for each operation,
  376. there is no problem. For example, it's the case for the Alpha processor:
  377. each floating-point instruction can specify a different rounding mode.
  378. However, the IEEE-754 Standard does not require such a behavior. So most of
  379. the FPUs only provide some instructions to set the rounding mode for all
  380. subsequent operations. And generally, these instructions need to flush the
  381. pipeline of the FPU.</p>
  382. <p>In this situation, the time needed to sum [<i>a</i>,<i>b</i>] and
  383. [<i>c</i>,<i>d</i>] is far worse than the time needed to calculate
  384. <i>a</i>+<i>b</i> and <i>c</i>+<i>d</i> since the two additions cannot be
  385. parallelized. Consequently, the objective is to diminish the number of
  386. rounding mode switches.</p>
  387. <p>If this library is not used to provide exact computations, but only for
  388. pair arithmetic, the solution is quite simple: do not use rounding. In that
  389. case, doing the sum [<i>a</i>,<i>b</i>] and [<i>c</i>,<i>d</i>] will be as
  390. fast as computing <i>a</i>+<i>b</i> and <i>c</i>+<i>d</i>. Everything is
  391. perfect.</p>
  392. <p>However, if exact computations are required, such a solution is totally
  393. unthinkable. So, are we penniless? No, there is still a trick available.
  394. Indeed, down(<i>a</i>+<i>c</i>) = -up(-<i>a</i>-<i>c</i>) if the unary
  395. minus is an exact operation. It is now possible to calculate the whole sum
  396. with the same rounding mode. Generally, the cost of the mode switching is
  397. worse than the cost of the sign changes.</p>
  398. <h4>Speeding up consecutive operations</h4>
  399. <p>The interval addition is not the only operation; most of the interval
  400. operations can be computed by setting the rounding direction of the FPU
  401. only once. So the operations of the floating point rounding policy assume
  402. that the direction is correctly set. This assumption is usually not true in
  403. a program (the user and the standard library expect the rounding direction
  404. to be to nearest), so these operations have to be enclosed in a shell that
  405. sets the floating point environment. This protection is done by the
  406. constructor and destructor of the rounding policy.</p>
  407. <p>Les us now consider the case of two consecutive interval additions:
  408. [<i>a</i>,<i>b</i>] + [<i>c</i>,<i>d</i>] + [<i>e</i>,<i>f</i>]. The
  409. generated code should look like:</p>
  410. <pre>
  411. init_rounding_mode(); // rounding object construction during the first addition
  412. t1 = -(-a - c);
  413. t2 = b + d;
  414. restore_rounding_mode(); // rounding object destruction
  415. init_rounding_mode(); // rounding object construction during the second addition
  416. x = -(-t1 - e);
  417. y = t2 + f;
  418. restore_rounding_mode(); // rounding object destruction
  419. // the result is the interval [x,y]
  420. </pre>
  421. <p>Between the two operations, the rounding direction is restored, and then
  422. initialized again. Ideally, compilers should be able to optimize this
  423. useless code away. But unfortunately they are not, and this slows the code
  424. down by an order of magnitude. In order to avoid this bottleneck, the user
  425. can tell to the interval operations that they do not need to be protected
  426. anymore. It will then be up to the user to protect the interval
  427. computations. The compiler will then be able to generate such a code:</p>
  428. <pre>
  429. init_rounding_mode(); // done by the user
  430. x = -(-a - c - e);
  431. y = b + d + f;
  432. restore_rounding_mode(); // done by the user
  433. </pre>
  434. <p>The user will have to create a rounding object. And as long as this
  435. object is alive, unprotected versions of the interval operations can be
  436. used. They are selected by using an interval type with a specific rounding
  437. policy. If the initial interval type is <code>I</code>, then
  438. <code>I::traits_type::rounding</code> is the type of the rounding object,
  439. and <code>interval_lib::unprotect&lt;I&gt;::type</code> is the type of the
  440. unprotected interval type.</p>
  441. <p>Because the rounding mode of the FPU is changed during the life of the
  442. rounding object, any arithmetic floating point operation that does not
  443. involve the interval library can lead to unexpected results. And
  444. reciprocally, using unprotected interval operation when no rounding object
  445. is alive will produce intervals that are not guaranteed anymore to contain
  446. the real result.</p>
  447. <h4 id="perfexp">Example</h4>
  448. <p>Here is an example of Horner's scheme to compute the value of a polynom.
  449. The rounding mode switches are disabled for the whole computation.</p>
  450. <pre>
  451. // I is an interval class, the polynom is a simple array
  452. template&lt;class I&gt;
  453. I horner(const I&amp; x, const I p[], int n) {
  454. // save and initialize the rounding mode
  455. typename I::traits_type::rounding rnd;
  456. // define the unprotected version of the interval type
  457. typedef typename boost::numeric::interval_lib::unprotect&lt;I&gt;::type R;
  458. const R&amp; a = x;
  459. R y = p[n - 1];
  460. for(int i = n - 2; i &gt;= 0; i--) {
  461. y = y * a + (const R&amp;)(p[i]);
  462. }
  463. return y;
  464. // restore the rounding mode with the destruction of rnd
  465. }
  466. </pre>
  467. <p>Please note that a rounding object is specially created in order to
  468. protect all the interval computations. Each interval of type I is converted
  469. in an interval of type R before any operations. If this conversion is not
  470. done, the result is still correct, but the interest of this whole
  471. optimization has disappeared. Whenever possible, it is good to convert to
  472. <code>const R&amp;</code> instead of <code>R</code>: indeed, the function
  473. could already be called inside an unprotection block so the types
  474. <code>R</code> and <code>I</code> would be the same interval, no need for a
  475. conversion.</p>
  476. <h4>Uninteresting remark</h4>
  477. <p>It was said at the beginning that the Alpha processors can use a
  478. specific rounding mode for each operation. However, due to the instruction
  479. format, the rounding toward plus infinity is not available. Only the
  480. rounding toward minus infinity can be used. So the trick using the change
  481. of sign becomes essential, but there is no need to save and restore the
  482. rounding mode on both sides of an operation.</p>
  483. <h3 id="extreg">Extended Registers</h3>
  484. <p>There is another problem besides the cost of the rounding mode switch.
  485. Some FPUs use extended registers (for example, float computations will be
  486. done with double registers, or double computations with long double
  487. registers). Consequently, many problems can arise.</p>
  488. <p>The first one is due to to the extended precision of the mantissa. The
  489. rounding is also done on this extended precision. And consequently, we
  490. still have down(<i>a</i>+<i>b</i>) = -up(-<i>a</i>-<i>b</i>) in the
  491. extended registers. But back to the standard precision, we now have
  492. down(<i>a</i>+<i>b</i>) &lt; -up(-<i>a</i>-<i>b</i>) instead of an
  493. equality. A solution could be not to use this method. But there still are
  494. other problems, with the comparisons between numbers for example.</p>
  495. <p>Naturally, there is also a problem with the extended precision of the
  496. exponent. To illustrate this problem, let <i>m</i> be the biggest number
  497. before +<i>inf</i>. If we calculate 2*[<i>m</i>,<i>m</i>], the answer
  498. should be [<i>m</i>,<i>inf</i>]. But due to the extended registers, the FPU
  499. will first store [<i>2m</i>,<i>2m</i>] and then convert it to
  500. [<i>inf</i>,<i>inf</i>] at the end of the calculus (when the rounding mode
  501. is toward +<i>inf</i>). So the answer is no more accurate.</p>
  502. <p>There is only one solution: to force the FPU to convert the extended
  503. values back to standard precision after each operation. Some FPUs provide
  504. an instruction able to do this conversion (for example the PowerPC
  505. processors). But for the FPUs that do not provide it (the x86 processors),
  506. the only solution is to write the values to memory and read them back. Such
  507. an operation is obviously very expensive.</p>
  508. <h2>Some Examples</h2>
  509. <p>Here come several cases:</p>
  510. <ul>
  511. <li>if you need precise computations with the <code>float</code> or
  512. <code>double</code> types, use the default
  513. <code>rounded_math&lt;T&gt;</code>;</li>
  514. <li>for fast wide intervals without any rounding nor precision, use
  515. <code>save_state_nothing&lt;rounded_transc_exact&lt;T&gt;
  516. &gt;</code>;</li>
  517. <li>for an exact type (like int or rational with a little help for
  518. infinite and NaN values) without support for transcendental functions,
  519. the solution could be
  520. <code>save_state_nothing&lt;rounded_transc_dummy&lt;T,
  521. rounded_arith_exact&lt;T&gt; &gt; &gt;</code> or directly
  522. <code>save_state_nothing&lt;rounded_arith_exact&lt;T&gt;
  523. &gt;</code>;</li>
  524. <li>if it is a more complex case than the previous ones, the best thing
  525. is probably to directly define your own policy.</li>
  526. </ul>
  527. <hr>
  528. <p><a href="http://validator.w3.org/check?uri=referer"><img border="0" src=
  529. "../../../../doc/images/valid-html401.png" alt="Valid HTML 4.01 Transitional"
  530. height="31" width="88"></a></p>
  531. <p>Revised
  532. <!--webbot bot="Timestamp" s-type="EDITED" s-format="%Y-%m-%d" startspan -->2006-12-24<!--webbot bot="Timestamp" endspan i-checksum="12172" --></p>
  533. <p><i>Copyright &copy; 2002 Guillaume Melquiond, Sylvain Pion, Herv&eacute;
  534. Br&ouml;nnimann, Polytechnic University<br>
  535. Copyright &copy; 2004-2005 Guillaume Melquiond, ENS Lyon</i></p>
  536. <p><i>Distributed under the Boost Software License, Version 1.0. (See
  537. accompanying file <a href="../../../../LICENSE_1_0.txt">LICENSE_1_0.txt</a>
  538. or copy at <a href=
  539. "http://www.boost.org/LICENSE_1_0.txt">http://www.boost.org/LICENSE_1_0.txt</a>)</i></p>
  540. </body>
  541. </html>