WPILibC++ 2024.3.2
log.hpp
Go to the documentation of this file.
1/*################################################################################
2 ##
3 ## Copyright (C) 2016-2023 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 natural logarithm function
23 */
24
25#ifndef _gcem_log_HPP
26#define _gcem_log_HPP
27
28#include <cmath>
29#include <type_traits>
30
31namespace gcem
32{
33
34namespace internal
35{
36
37// continued fraction seems to be a better approximation for small x
38// see http://functions.wolfram.com/ElementaryFunctions/Log/10/0005/
39
40#if __cplusplus >= 201402L // C++14 version
41
42template<typename T>
43constexpr
44T
45log_cf_main(const T xx, const int depth_end)
46noexcept
47{
48 int depth = GCEM_LOG_MAX_ITER_SMALL - 1;
49 T res = T(2*(depth+1) - 1);
50
51 while (depth > depth_end - 1) {
52 res = T(2*depth - 1) - T(depth*depth) * xx / res;
53
54 --depth;
55 }
56
57 return res;
58}
59
60#else // C++11 version
61
62template<typename T>
63constexpr
64T
65log_cf_main(const T xx, const int depth)
66noexcept
67{
68 return( depth < GCEM_LOG_MAX_ITER_SMALL ? \
69 // if
70 T(2*depth - 1) - T(depth*depth) * xx / log_cf_main(xx,depth+1) :
71 // else
72 T(2*depth - 1) );
73}
74
75#endif
76
77template<typename T>
78constexpr
79T
80log_cf_begin(const T x)
81noexcept
82{
83 return( T(2)*x/log_cf_main(x*x,1) );
84}
85
86template<typename T>
87constexpr
88T
89log_main(const T x)
90noexcept
91{
92 return( log_cf_begin((x - T(1))/(x + T(1))) );
93}
94
95constexpr
96long double
98noexcept
99{
100 return( x == 2 ? 0.6931471805599453094172321214581765680755L :
101 x == 3 ? 1.0986122886681096913952452369225257046475L :
102 x == 4 ? 1.3862943611198906188344642429163531361510L :
103 x == 5 ? 1.6094379124341003746007593332261876395256L :
104 x == 6 ? 1.7917594692280550008124773583807022727230L :
105 x == 7 ? 1.9459101490553133051053527434431797296371L :
106 x == 8 ? 2.0794415416798359282516963643745297042265L :
107 x == 9 ? 2.1972245773362193827904904738450514092950L :
108 x == 10 ? 2.3025850929940456840179914546843642076011L :
109 0.0L );
110}
111
112template<typename T>
113constexpr
114T
115log_mantissa(const T x)
116noexcept
117{ // divide by the integer part of x, which will be in [1,10], then adjust using tables
118 return( log_main(x/T(static_cast<int>(x))) + T(log_mantissa_integer(static_cast<int>(x))) );
119}
120
121template<typename T>
122constexpr
123T
124log_breakup(const T x)
125noexcept
126{ // x = a*b, where b = 10^c
127 return( log_mantissa(mantissa(x)) + T(GCEM_LOG_10)*T(find_exponent(x,0)) );
128}
129
130template<typename T>
131constexpr
132T
133log_check(const T x)
134noexcept
135{
136 return( is_nan(x) ? \
138 // x < 0
139 x < T(0) ? \
141 // x ~= 0
142 GCLIM<T>::min() > x ? \
144 // indistinguishable from 1
145 GCLIM<T>::min() > abs(x - T(1)) ? \
146 T(0) :
147 //
148 x == GCLIM<T>::infinity() ? \
150 // else
151 (x < T(0.5) || x > T(1.5)) ?
152 // if
153 log_breakup(x) :
154 // else
155 log_main(x) );
156}
157
158template<typename T>
159constexpr
162noexcept
163{
164 return( std::is_integral<T>::value ? \
165 x == T(0) ? \
166 - GCLIM<return_t<T>>::infinity() :
167 x > T(1) ? \
168 log_check( static_cast<return_t<T>>(x) ) :
169 static_cast<return_t<T>>(0) :
170 log_check( static_cast<return_t<T>>(x) ) );
171}
172
173}
174
175/**
176 * Compile-time natural logarithm function
177 *
178 * @param x a real-valued input.
179 * @return \f$ \log_e(x) \f$ using \f[ \log\left(\frac{1+x}{1-x}\right) = \dfrac{2x}{1-\dfrac{x^2}{3-\dfrac{4x^2}{5 - \dfrac{9x^3}{7 - \ddots}}}}, \ \ x \in [-1,1] \f]
180 * The continued fraction argument is split into two parts: \f$ x = a \times 10^c \f$, where \f$ c \f$ is an integer.
181 */
182
183template<typename T>
184constexpr
185return_t<T>
186log(const T x)
187noexcept
188{
191 } else {
192 return std::log(x);
193 }
194}
195
196}
197
198#endif
#define GCEM_LOG_MAX_ITER_SMALL
Definition: gcem_options.hpp:153
#define GCEM_LOG_10
Definition: gcem_options.hpp:94
constexpr FMT_INLINE auto is_constant_evaluated(bool default_value=false) noexcept -> bool
Definition: core.h:304
constexpr T log_cf_main(const T xx, const int depth) noexcept
Definition: log.hpp:65
constexpr T log_mantissa(const T x) noexcept
Definition: log.hpp:115
constexpr T log_cf_begin(const T x) noexcept
Definition: log.hpp:80
constexpr T mantissa(const T x) noexcept
Definition: mantissa.hpp:37
constexpr bool is_nan(const T x) noexcept
Definition: is_nan.hpp:39
constexpr T log_check(const T x) noexcept
Definition: log.hpp:133
constexpr llint_t find_exponent(const T x, const llint_t exponent) noexcept
Definition: find_exponent.hpp:37
constexpr long double log_mantissa_integer(const int x) noexcept
Definition: log.hpp:97
constexpr T log_breakup(const T x) noexcept
Definition: log.hpp:124
constexpr T log_main(const T x) noexcept
Definition: log.hpp:89
constexpr return_t< T > log_integral_check(const T x) noexcept
Definition: log.hpp:161
Definition: is_even.hpp:29
constexpr T abs(const T x) noexcept
Compile-time absolute value function.
Definition: abs.hpp:40
constexpr return_t< T > log(const T x) noexcept
Compile-time natural logarithm function.
Definition: log.hpp:186
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