]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | [section:ct_pow Compile Time Power of a Runtime Base] |
2 | ||
3 | The `pow` function effectively computes the compile-time integral | |
4 | power of a run-time base. | |
5 | ||
6 | [h4 Synopsis] | |
7 | ||
8 | [@../../../../boost/math/special_functions/pow.hpp `#include <boost/math/special_functions/pow.hpp>`] | |
9 | ||
10 | namespace boost { namespace math { | |
11 | ||
12 | template <int N, typename T> | |
13 | ``__sf_result`` pow(T base); | |
14 | ||
15 | template <int N, typename T, class Policy> | |
16 | ``__sf_result`` pow(T base, const Policy& policy); | |
17 | ||
18 | }} | |
19 | ||
20 | [h4 Rationale and Usage] | |
21 | ||
22 | Computing the power of a number with an exponent that is known | |
23 | at compile time is a common need for programmers. In such cases, | |
24 | the usual method is to avoid the overhead implied by | |
25 | the `pow`, `powf` and `powl` C functions by hardcoding an expression | |
26 | such as: | |
27 | ||
28 | // Hand-written 8th power of a 'base' variable | |
29 | double result = base*base*base*base*base*base*base*base; | |
30 | ||
31 | However, this kind of expression is not really readable (knowing the | |
32 | value of the exponent involves counting the number of occurrences of /base/), | |
33 | error-prone (it's easy to forget an occurrence), syntactically bulky, and | |
34 | non-optimal in terms of performance. | |
35 | ||
36 | The pow function of Boost.Math helps writing this kind expression along | |
37 | with solving all the problems listed above: | |
38 | ||
39 | // 8th power of a 'base' variable using math::pow | |
40 | double result = pow<8>(base); | |
41 | ||
42 | The expression is now shorter, easier to read, safer, and even faster. | |
43 | Indeed, `pow` will compute the expression such that only log2(N) | |
44 | products are made for a power of N. For instance in the | |
45 | example above, the resulting expression will be the same as if we had | |
46 | written this, with only one computation of each identical subexpression: | |
47 | ||
48 | // Internal effect of pow<8>(base) | |
49 | double result = ((base*base)*(base*base))*((base*base)*(base*base)); | |
50 | ||
51 | Only 3 different products were actually computed. | |
52 | ||
53 | ||
54 | [h4 Return Type] | |
55 | ||
56 | The return type of these functions is computed using the __arg_promotion_rules. | |
57 | For example: | |
58 | ||
59 | * If T is a `float`, the return type is a `float`. | |
60 | * If T is a `long double`, the return type is a `long double`. | |
61 | * Otherwise, the return type is a `double`. | |
62 | ||
63 | [h4 Policies] | |
64 | ||
65 | [optional_policy] | |
66 | ||
67 | [h4 Error Handling] | |
68 | ||
69 | Two cases of errors can occur when using `pow`: | |
70 | ||
71 | * In case of null base and negative exponent, an __overflow_error occurs since | |
72 | this operation is a division by 0 (it equals to 1/0). | |
73 | * In case of null base and null exponent, an __indeterminate_result_error | |
74 | occurs since the result of this operation is indeterminate. | |
75 | Those errors follow the | |
76 | [link math_toolkit.error_handling | |
77 | general policies of error handling in Boost.Math]. | |
78 | ||
79 | The default overflow error policy is `throw_on_error`. A call like `pow<-2>(0)` | |
80 | will thus throw a `std::overflow_error` exception. As shown in the | |
81 | link given above, other error handling policies can be used: | |
82 | ||
83 | * `errno_on_error`: Sets `::errno` to `ERANGE` and returns `std::numeric_limits<T>::infinity()`. | |
84 | * `ignore_error`: Returns `std::numeric_limits<T>::infinity()`. | |
85 | * `user_error`: Returns the result of `boost::math::policies::user_overflow_error`: | |
86 | this function must be defined by the user. | |
87 | ||
88 | The default indeterminate result error policy is `ignore_error`, which for this | |
89 | function returns 1 since it's the most commonly chosen result for a power of 0. | |
90 | Here again, other error handling policies can be used: | |
91 | ||
92 | * `throw_on_error`: Throws `std::domain_error` | |
93 | * `errno_on_error`: Sets `::errno` to `EDOM` and returns 1. | |
94 | * `user_error`: Returns the result of `boost::math::policies::user_indeterminate_result_error`: | |
95 | this function must be defined by the user. | |
96 | ||
97 | Here is an example of error handling customization where we want to | |
98 | specify the result that has to be returned in case of error. We will | |
99 | thus use the `user_error` policy, by passing as second argument an | |
100 | instance of an overflow_error policy templated with `user_error`: | |
101 | ||
102 | // First we open the boost::math::policies namespace and define the `user_overflow_error` | |
103 | // by making it return the value we want in case of error (-1 here) | |
104 | ||
105 | namespace boost { namespace math { namespace policies { | |
106 | template <class T> | |
107 | T user_overflow_error(const char*, const char*, const T&) | |
108 | { return -1; } | |
109 | }}} | |
110 | ||
111 | ||
112 | // Then we invoke pow and indicate that we want to use the user_error policy | |
113 | using boost::math::policies; | |
114 | double result = pow<-5>(base, policy<overflow_error<user_error> >()); | |
115 | ||
116 | // We can now test the returned value and treat the special case if needed: | |
117 | if (result == -1) | |
118 | { | |
119 | // there was an error, do something... | |
120 | } | |
121 | ||
122 | Another way is to redefine the default `overflow_error` policy by using the | |
123 | BOOST_MATH_OVERFLOW_ERROR_POLICY macro. Once the `user_overflow_error` function | |
124 | is defined as above, we can achieve the same result like this: | |
125 | ||
126 | // Redefine the default error_overflow policy | |
127 | #define BOOST_MATH_OVERFLOW_ERROR_POLICY user_error | |
128 | #include <boost/math/special_functions/pow.hpp> | |
129 | ||
130 | // From this point, passing a policy in argument is no longer needed, a call like this one | |
131 | // will return -1 in case of error: | |
132 | ||
133 | double result = pow<-5>(base); | |
134 | ||
135 | ||
136 | [h4 Acknowledgements] | |
137 | ||
138 | Bruno Lalande submitted this addition to Boost.Math. | |
139 | ||
140 | ''' | |
141 | Thanks to Joaquín López Muñoz and Scott McMurray for their help in | |
142 | improving the implementation. | |
143 | ''' | |
144 | ||
145 | [h4 References] | |
146 | ||
147 | D.E. Knuth, ['The Art of Computer Programming, Vol. 2: Seminumerical Algorithms], 2nd ed., Addison-Wesley, Reading, MA, 1981 | |
148 | ||
149 | [endsect] | |
150 | ||
151 | [/ | |
152 | Copyright 2008 Bruno Lalande. | |
153 | Distributed under the Boost Software License, Version 1.0. | |
154 | (See accompanying file LICENSE_1_0.txt or copy at | |
155 | http://www.boost.org/LICENSE_1_0.txt). | |
156 | ] | |
157 |