WPILibC++ 2025.2.1
Loading...
Searching...
No Matches
atan.hpp
Go to the documentation of this file.
1/*################################################################################
2 ##
3 ## Copyright (C) 2016-2024 Keith O'Hara
4 ##
5 ## This file is part of the GCE-Math C++ library.
6 ##
7 ## Licensed under the Apache License, Version 2.0 (the "License");
8 ## you may not use this file except in compliance with the License.
9 ## You may obtain a copy of the License at
10 ##
11 ## http://www.apache.org/licenses/LICENSE-2.0
12 ##
13 ## Unless required by applicable law or agreed to in writing, software
14 ## distributed under the License is distributed on an "AS IS" BASIS,
15 ## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 ## See the License for the specific language governing permissions and
17 ## limitations under the License.
18 ##
19 ################################################################################*/
20
21/*
22 * compile-time arctangent function
23 */
24
25// see
26// http://functions.wolfram.com/ElementaryFunctions/ArcTan/10/0001/
27// http://functions.wolfram.com/ElementaryFunctions/ArcTan/06/01/06/01/0002/
28
29#ifndef _gcem_atan_HPP
30#define _gcem_atan_HPP
31
32#include <cmath>
33#include <type_traits>
34
35namespace gcem
36{
37
38namespace internal
39{
40
41// Series
42
43template<typename T>
44constexpr
45T
46atan_series_order_calc(const T xx, const T x_pow, const uint_t order)
47noexcept
48{
49 return( T(1)/( T((order-1)*4 - 1) * x_pow ) \
50 - T(1)/( T((order-1)*4 + 1) * x_pow * xx) );
51}
52
53#if __cplusplus >= 201402L // C++14 version
54
55template<typename T>
56constexpr
57T
58atan_series_order(const T x, const T x_pow, const uint_t order_begin, const uint_t max_order)
59noexcept
60{
61 // run in reverse order to sum smallest numbers first
62
63 if (max_order == 1) {
64 return GCEM_HALF_PI - T(1)/x_pow; // use x_pow to avoid a warning
65 }
66
67 T xx = x*x;
68 T res = atan_series_order_calc(xx, pow(x,4*max_order-5), max_order);
69
70 uint_t depth = max_order - 1;
71
72 while (depth > order_begin) {
73 res += atan_series_order_calc(xx, pow(x,4*depth-5), depth);
74
75 --depth;
76 }
77
78 res += GCEM_HALF_PI - T(1)/x;
79
80 return res;
81}
82
83#else // C++11 version
84
85template<typename T>
86constexpr
87T
88atan_series_order(const T x, const T x_pow, const uint_t order, const uint_t max_order)
89noexcept
90{
91 return( max_order == 1 ? \
92 T(GCEM_HALF_PI) - T(1)/x :
93 order == 1 ? \
94 T(GCEM_HALF_PI) - T(1)/x + atan_series_order(x*x,pow(x,3),order+1,max_order) :
95 // NOTE: x changes to x*x for order > 1
96 order < max_order ? \
97 atan_series_order_calc(x,x_pow,order) \
98 + atan_series_order(x,x_pow*x*x,order+1,max_order) :
99 // order == max_order
100 atan_series_order_calc(x,x_pow,order) );
101}
102
103#endif
104
105template<typename T>
106constexpr
107T
109noexcept
110{
111 return( x < T(3) ? atan_series_order(x,x,1U,10U) : // O(1/x^39)
112 x < T(4) ? atan_series_order(x,x,1U,9U) : // O(1/x^35)
113 x < T(5) ? atan_series_order(x,x,1U,8U) : // O(1/x^31)
114 x < T(7) ? atan_series_order(x,x,1U,7U) : // O(1/x^27)
115 x < T(11) ? atan_series_order(x,x,1U,6U) : // O(1/x^23)
116 x < T(25) ? atan_series_order(x,x,1U,5U) : // O(1/x^19)
117 x < T(100) ? atan_series_order(x,x,1U,4U) : // O(1/x^15)
118 x < T(1000) ? atan_series_order(x,x,1U,3U) : // O(1/x^11)
119 atan_series_order(x,x,1U,2U) ); // O(1/x^7)
120}
121
122// CF
123
124#if __cplusplus >= 201402L // C++14 version
125
126template<typename T>
127constexpr
128T
129atan_cf_recur(const T xx, const uint_t depth_begin, const uint_t max_depth)
130noexcept
131{
132 uint_t depth = max_depth - 1;
133 T res = T(2*(depth+1) - 1);
134
135 while (depth > depth_begin - 1) {
136 res = T(2*depth - 1) + T(depth*depth) * xx / res;
137
138 --depth;
139 }
140
141 return res;
142}
143
144#else // C++11 version
145
146template<typename T>
147constexpr
148T
149atan_cf_recur(const T xx, const uint_t depth, const uint_t max_depth)
150noexcept
151{
152 return( depth < max_depth ? \
153 // if
154 T(2*depth - 1) + T(depth*depth) * xx / atan_cf_recur(xx,depth+1,max_depth) :
155 // else
156 T(2*depth - 1) );
157}
158
159#endif
160
161template<typename T>
162constexpr
163T
164atan_cf_main(const T x)
165noexcept
166{
167 return( x < T(0.5) ? x/atan_cf_recur(x*x, 1U, 15U ) :
168 x < T(1) ? x/atan_cf_recur(x*x, 1U, 25U ) :
169 x < T(1.5) ? x/atan_cf_recur(x*x, 1U, 35U ) :
170 x < T(2) ? x/atan_cf_recur(x*x, 1U, 45U ) :
171 x/atan_cf_recur(x*x, 1U, 52U ) );
172}
173
174// choose between series expansion and continued fraction
175
176template<typename T>
177constexpr
178T
179atan_begin(const T x)
180noexcept
181{
182 return( x > T(2.5) ? atan_series_main(x) : atan_cf_main(x) );
183}
184
185// check input
186
187template<typename T>
188constexpr
189T
190atan_check(const T x)
191noexcept
192{
193 return( // NaN check
194 is_nan(x) ? \
196 // indistinguishable from zero
197 GCLIM<T>::min() > abs(x) ? \
198 T(0) :
199 // negative or positive
200 x < T(0) ? \
201 - atan_begin(-x) :
202 atan_begin( x) );
203}
204
205}
206
207/**
208 * Compile-time arctangent function
209 *
210 * @param x a real-valued input.
211 * @return the inverse tangent function using \f[ \text{atan}(x) = \dfrac{x}{1 + \dfrac{x^2}{3 + \dfrac{4x^2}{5 + \dfrac{9x^2}{7 + \ddots}}}} \f]
212 */
213
214template<typename T>
215constexpr
217atan(const T x)
218noexcept
219{
220 if (std::is_constant_evaluated()) {
221 return internal::atan_check( static_cast<return_t<T>>(x) );
222 } else {
223 return std::atan(x);
224 }
225}
226
227}
228
229#endif
#define GCEM_HALF_PI
Definition gcem_options.hpp:118
constexpr T atan_check(const T x) noexcept
Definition atan.hpp:190
constexpr T atan_cf_main(const T x) noexcept
Definition atan.hpp:164
constexpr T atan_cf_recur(const T xx, const uint_t depth, const uint_t max_depth) noexcept
Definition atan.hpp:149
constexpr bool is_nan(const T x) noexcept
Definition is_nan.hpp:39
constexpr T atan_series_main(const T x) noexcept
Definition atan.hpp:108
constexpr T atan_series_order_calc(const T xx, const T x_pow, const uint_t order) noexcept
Definition atan.hpp:46
constexpr T atan_begin(const T x) noexcept
Definition atan.hpp:179
constexpr T atan_series_order(const T x, const T x_pow, const uint_t order, const uint_t max_order) noexcept
Definition atan.hpp:88
Definition is_odd.hpp:29
unsigned int uint_t
Definition gcem_options.hpp:68
constexpr T abs(const T x) noexcept
Compile-time absolute value function.
Definition abs.hpp:40
constexpr return_t< T > atan(const T x) noexcept
Compile-time arctangent function.
Definition atan.hpp:217
std::numeric_limits< T > GCLIM
Definition gcem_options.hpp:74
typename std::conditional< std::is_integral< T >::value, double, T >::type return_t
Definition gcem_options.hpp:77
constexpr common_t< T1, T2 > pow(const T1 base, const T2 exp_term) noexcept
Compile-time power function.
Definition pow.hpp:82