1- // Copyright 2023 Matt Borland
2- // Copyright 2023 Christopher Kormanyos
1+ // Copyright 2023 - 2024 Matt Borland
2+ // Copyright 2023 - 2024 Christopher Kormanyos
33// Distributed under the Boost Software License, Version 1.0.
44// https://www.boost.org/LICENSE_1_0.txt
55
66#ifndef BOOST_DECIMAL_DETAIL_CMATH_ATAN_HPP
77#define BOOST_DECIMAL_DETAIL_CMATH_ATAN_HPP
88
9- #include < boost/decimal/fwd.hpp>
10- #include < boost/decimal/numbers.hpp>
11- #include < boost/decimal/detail/type_traits.hpp>
9+ #include < boost/decimal/fwd.hpp> // NOLINT(llvm-include-order)
10+ #include < boost/decimal/detail/cmath/impl/atan_impl.hpp>
1211#include < boost/decimal/detail/concepts.hpp>
1312#include < boost/decimal/detail/config.hpp>
14- #include < boost/decimal/detail/cmath/fpclassify .hpp>
15- #include < boost/decimal/detail/cmath/fabs .hpp>
13+ #include < boost/decimal/detail/type_traits .hpp>
14+ #include < boost/decimal/numbers .hpp>
1615
1716#ifndef BOOST_DECIMAL_BUILD_MODULE
1817#include < type_traits>
@@ -27,205 +26,94 @@ namespace detail {
2726template <BOOST_DECIMAL_DECIMAL_FLOATING_TYPE T>
2827constexpr auto atan_small_impl (T x) noexcept
2928{
30- T result {};
31-
32- // 10th degree remez polynomial calculated from 0, 0.4375
33- // Estimated max error: 2.3032664387910605e-12
34- constexpr T a0 {UINT64_C (61037779951304161 ), -18 , true };
35- constexpr T a1 {UINT64_C (10723099589331457 ), -17 };
36- constexpr T a2 {UINT64_C (22515613909953665 ), -18 };
37- constexpr T a3 {UINT64_C (15540713402718176 ), -17 , true };
38- constexpr T a4 {UINT64_C (35999727706986597 ), -19 };
39- constexpr T a5 {UINT64_C (19938867353282852 ), -17 };
40- constexpr T a6 {UINT64_C (62252075283915644 ), -22 };
41- constexpr T a7 {UINT64_C (33333695504913247 ), -17 , true };
42- constexpr T a8 {UINT64_C (10680927642397763 ), -24 };
43- constexpr T a9 {UINT64_C (99999999877886492 ), -17 };
44- constexpr T a10 {UINT64_C (23032664387910606 ), -29 };
45-
46- result = a0;
47- result = fma (result, x, a1);
48- result = fma (result, x, a2);
49- result = fma (result, x, a3);
50- result = fma (result, x, a4);
51- result = fma (result, x, a5);
52- result = fma (result, x, a6);
53- result = fma (result, x, a7);
54- result = fma (result, x, a8);
55- result = fma (result, x, a9);
56- result = fma (result, x, a10);
57-
58- return result;
29+ return detail::atan_series_small (x);
5930}
6031
6132template <BOOST_DECIMAL_DECIMAL_FLOATING_TYPE T>
6233constexpr auto atan_med_impl (T x) noexcept
6334{
64- T result {};
65-
66- // 10th degree remez polynomial from 2.4375, 6
67- // Estimated max error: 2.6239664084435361e-9
68- constexpr T a0 {UINT64_C (35895331641408534 ), -24 , true };
69- constexpr T a1 {UINT64_C (1734850544519432 ), -21 };
70- constexpr T a2 {UINT64_C (38064221484608425 ), -21 , true };
71- constexpr T a3 {UINT64_C (50135011697517902 ), -20 };
72- constexpr T a4 {UINT64_C (44154446962804779 ), -19 , true };
73- constexpr T a5 {UINT64_C (27400572833763747 ), -18 };
74- constexpr T a6 {UINT64_C (12289830364128736 ), -17 , true };
75- constexpr T a7 {UINT64_C (40157034119189716 ), -17 };
76- constexpr T a8 {UINT64_C (94842703533437844 ), -17 , true };
77- constexpr T a9 {UINT64_C (15738722141839421 ), -16 };
78- constexpr T a10 {UINT64_C (1425850153011925 ), -16 , true };
79-
80- result = a0;
81- result = fma (result, x, a1);
82- result = fma (result, x, a2);
83- result = fma (result, x, a3);
84- result = fma (result, x, a4);
85- result = fma (result, x, a5);
86- result = fma (result, x, a6);
87- result = fma (result, x, a7);
88- result = fma (result, x, a8);
89- result = fma (result, x, a9);
90- result = fma (result, x, a10);
91-
92- return result;
93- }
94-
95- template <BOOST_DECIMAL_DECIMAL_FLOATING_TYPE T>
96- constexpr auto atan_large_impl (T x) noexcept
97- {
98- T result {};
99-
100- // 10th degree remez polynomial from 6, 12
101- // Estimated max error: 6.2743529396040705e-10
102- constexpr T a0 {UINT64_C (33711825733904967 ), -27 , true };
103- constexpr T a1 {UINT64_C (33373728162443893 ), -25 };
104- constexpr T a2 {UINT64_C (14947421096171872 ), -23 , true };
105- constexpr T a3 {UINT64_C (39987662607208282 ), -22 };
106- constexpr T a4 {UINT64_C (7102051362837618 ), -20 , true };
107- constexpr T a5 {UINT64_C (87975481286276403 ), -20 };
108- constexpr T a6 {UINT64_C (77627729565466572 ), -19 , true };
109- constexpr T a7 {UINT64_C (48865382040050205 ), -18 };
110- constexpr T a8 {UINT64_C (21563130284459425 ), -17 , true };
111- constexpr T a9 {UINT64_C (63862756812924015 ), -17 };
112- constexpr T a10 {UINT64_C (41486607456081259 ), -17 };
113-
114- result = a0;
115- result = fma (result, x, a1);
116- result = fma (result, x, a2);
117- result = fma (result, x, a3);
118- result = fma (result, x, a4);
119- result = fma (result, x, a5);
120- result = fma (result, x, a6);
121- result = fma (result, x, a7);
122- result = fma (result, x, a8);
123- result = fma (result, x, a9);
124- result = fma (result, x, a10);
125-
126- return result;
127- }
128-
129- template <BOOST_DECIMAL_DECIMAL_FLOATING_TYPE T>
130- constexpr auto atan_huge_impl (T x) noexcept
131- {
132- T result {};
133-
134- // 10th degree remez polynomial from 12, 24
135- // Estimated max error: 4.1947468509456082e-10
136- constexpr T a0 {UINT64_C (21000582873393547 ), -30 , true };
137- constexpr T a1 {UINT64_C (41414963913943078 ), -28 };
138- constexpr T a2 {UINT64_C (36923801494687764 ), -26 , true };
139- constexpr T a3 {UINT64_C (19644631420406287 ), -24 };
140- constexpr T a4 {UINT64_C (69300227486259428 ), -23 , true };
141- constexpr T a5 {UINT64_C (17021586749644597 ), -21 };
142- constexpr T a6 {UINT64_C (29708833721842521 ), -20 , true };
143- constexpr T a7 {UINT64_C (36858037393285633 ), -19 };
144- constexpr T a8 {UINT64_C (31874262996720311 ), -18 , true };
145- constexpr T a9 {UINT64_C (18322547884211479 ), -17 };
146- constexpr T a10 {UINT64_C (9387703660037886 ), -16 };
147-
148- result = a0;
149- result = fma (result, x, a1);
150- result = fma (result, x, a2);
151- result = fma (result, x, a3);
152- result = fma (result, x, a4);
153- result = fma (result, x, a5);
154- result = fma (result, x, a6);
155- result = fma (result, x, a7);
156- result = fma (result, x, a8);
157- result = fma (result, x, a9);
158- result = fma (result, x, a10);
159-
160- return result;
35+ return detail::atan_series_med (x);
16136}
16237
16338template <typename T>
164- constexpr auto atan_impl (T x) noexcept
39+ constexpr auto atan_impl_cases (T x) noexcept
16540 BOOST_DECIMAL_REQUIRES(detail::is_decimal_floating_point_v, T)
16641{
167- const auto fpc {fpclassify (x)};
168- const auto isneg {signbit (x)};
169-
170- if (fpc == FP_ZERO || fpc == FP_NAN)
171- {
172- return x;
173- }
174- else if (fpc == FP_INFINITE)
175- {
176- constexpr auto half_pi {numbers::pi_v<T> / 2 };
177- return isneg ? -half_pi : half_pi;
178- }
179-
180- // Small angles
181- const auto absx {fabs (x)};
182- T result {};
183-
184- if (absx <= std::numeric_limits<T>::epsilon ())
42+ if (x <= std::numeric_limits<T>::epsilon ())
18543 {
18644 return x;
18745 }
188- else if (absx <= T{ 4375 , -4 })
46+ else if (x <= T { 4375 , -4 })
18947 {
190- result = detail::atan_small_impl (absx );
48+ return detail::atan_small_impl (x );
19149 }
192- else if (absx <= T{ 6875 , -4 })
50+ else if (x <= T { 6875 , -4 })
19351 {
194- constexpr T atan_half {UINT64_C (4636476090008061162 ), -19 };
195- result = atan_half + detail::atan_small_impl ((x - T{5 , -1 }) / (1 + x / 2 ));
52+ constexpr T atan_half { UINT64_C (4636476090008061162 ), -19 };
53+
54+ return atan_half + detail::atan_small_impl ((x - T{5 , -1 }) / (1 + x / 2 ));
19655 }
197- else if (absx <= T{11875 , -4 })
56+ else if (x <= T{11875 , -4 })
19857 {
19958 constexpr T atan_one {UINT64_C (7853981633974483096 ), -19 };
200- result = atan_one + detail::atan_small_impl ((x - 1 ) / (x + 1 ));
59+
60+ return atan_one + detail::atan_small_impl ((x - 1 ) / (x + 1 ));
20161 }
202- else if (absx <= T{ 24375 , -4 })
62+ else if (x <= T { 24375 , -4 })
20363 {
20464 constexpr T atan_three_halves {UINT64_C (9827937232473290679 ), -19 };
205- result = atan_three_halves + detail::atan_small_impl ((x - T{15 , -1 }) / (1 + T{15 , -1 } * x));
65+
66+ return atan_three_halves + detail::atan_small_impl ((x - T{15 , -1 }) / (1 + T{15 , -1 } * x));
20667 }
207- else if (absx <= T{ 6 })
68+ else
20869 {
209- result = detail::atan_med_impl (x);
70+ // x <= T { 6 }
71+ return detail::atan_med_impl (x);
21072 }
211- else if (absx <= T{12 })
73+ }
74+
75+ template <typename T>
76+ constexpr auto atan_impl (T x) noexcept
77+ BOOST_DECIMAL_REQUIRES(detail::is_decimal_floating_point_v, T)
78+ {
79+ const auto fpc { fpclassify (x) };
80+
81+ T result { };
82+
83+ constexpr T my_pi_half { numbers::pi_v<T> / 2 };
84+
85+ if (fpc == FP_ZERO || fpc == FP_NAN)
21286 {
213- result = detail::atan_large_impl (x) ;
87+ result = x ;
21488 }
215- else if (absx <= T{ 24 } )
89+ else if (signbit (x) )
21690 {
217- result = detail::atan_huge_impl ( x);
91+ result = - atan_impl (- x);
21892 }
219- else
93+ else if (fpc == FP_INFINITE)
22094 {
221- constexpr T atan_inf {numbers::pi_v<T> / 2 };
222- result = atan_inf - detail::atan_small_impl (1 / x);
95+ result = my_pi_half;
22396 }
224-
225- // arctan(-x) == -arctan(x)
226- if (isneg)
97+ else
22798 {
228- result = -result;
99+ if (x <= T { 6 })
100+ {
101+ result = atan_impl_cases (x);
102+ }
103+ else if (x <= T { 24 })
104+ {
105+ // The algorithm for arc-tangent of large-valued argument is based
106+ // on Chapter 11, page 194 of Cody and Waite, "Software Manual
107+ // for the Elementary Functions", Prentice Hall, 1980.
108+
109+ const T f { ((x * numbers::sqrt3_v<T>) - T { 1 }) / (numbers::sqrt3_v<T> + x) };
110+
111+ result = (numbers::pi_v<T> / static_cast <int >(INT8_C (6 ))) + atan_impl_cases (f);
112+ }
113+ else
114+ {
115+ result = my_pi_half - detail::atan_small_impl (1 / x);
116+ }
229117 }
230118
231119 return result;
0 commit comments