GCC Code Coverage Report


Directory: include/polyfloat/
File: include/polyfloat/module/math/atan.hpp
Date: 2026-11-09 15:28:50
Exec Total Coverage
Lines: 25 25 100.0%
Functions: 44 44 100.0%
Branches: 0 0 -%

Line Branch Exec Source
1 //======================================================================================================================
2 /*
3 POLYFLOAT - Extended precision floating points
4 Copyright : POLYFLOAT Contributors & Maintainers
5 SPDX-License-Identifier: BSL-1.0
6 */
7 //======================================================================================================================
8 #pragma once
9
10 #include <polyfloat/details/callable.hpp>
11 #include <polyfloat/types/concepts.hpp>
12 #include <polyfloat/types/traits.hpp>
13 #include <type_traits>
14 #include <polyfloat/module/math/tan.hpp>
15
16 namespace plf
17 {
18
19 template<typename Options>
20 struct atan_t : plf::elementwise_callable<atan_t,
21 eve::atan_t,
22 Options,
23 raw_option,
24 pedantic_option,
25 eve::rad_option,
26 eve::radpi_option,
27 eve::deg_option>
28 {
29 37366 template<concepts::polyfloat_like Z> POLYFLOAT_ABI constexpr Z operator()(Z z) const noexcept
30 {
31 37366 return POLYFLOAT_CALL(z);
32 }
33
34 37356 POLYFLOAT_CALLABLE_OBJECT(atan_t, atan_);
35 };
36 //======================================================================================================================
37 //! @addtogroup math
38 //! @{
39 //! @var atan
40 //! @brief return the arctangent value.
41 //!
42 //! @groupheader{Header file}
43 //!
44 //! @code
45 //! #include <polyfloat/core.hpp>
46 //! @endcode
47 //!
48 //! @groupheader{Callable Signatures}
49 //!
50 //! @code
51 //! namespace polyfloat
52 //! {
53 //! template<polyfloat::concepts::polyfloat_like T> constexpr auto atan(T z) noexcept;
54 //! }
55 //! @endcode
56 //!
57 //! **Parameters**
58 //!
59 //! * `z`: Value to process.
60 //!
61 //! **Return value**
62 //!
63 //! Returns the arctangent of z.
64 //!
65 //! @groupheader{Example}
66 //!
67 //! @godbolt{doc/math/atan.cpp}
68 //======================================================================================================================
69
70 inline constexpr auto atan = eve::functor<atan_t>;
71 //======================================================================================================================
72 //! @}
73 //======================================================================================================================
74 }
75
76 namespace plf::_
77 {
78 // take the absolute value atan(-x) = -atan(x) -> ax > 0
79 // restrain ax to < 1 atan(ax) = pi/2-atan(1/ax) -> 0 <= axx <= 1
80 // restrain axx to [0, sqrt(2)-1] atan(axx) = pi/4 - atan((1-axxx)/(1+axx)) and axxx < sqrt(2)-1
81 // use 1 or 2 newton steps to reach precision
82 //Perhaps 2 imprvt to see latter
83 // 1 treat small values differently
84 // 2 the three steps can be progressive T, double_real_t<T> and triple_real_t<T>
85 37356 template<typename T, eve::callable_options O> constexpr auto atan_(POLYFLOAT_DELAY(), O const& o, T a0) noexcept
86 {
87 if constexpr (O::contains(eve::rad)) return atan[o.drop(rad)](a0);
88 else if constexpr (O::contains(eve::deg)) return radindeg(atan[o.drop(eve::deg)](a0));
89 else if constexpr (O::contains(eve::radpi)) return radinpi(atan[o.drop(eve::radpi)](a0));
90 else
91 {
92 37356 auto a0pos = plf::is_positive(a0);
93 37356 auto ax = plf::abs(a0);
94 37356 auto invax = ax > plf::one(eve::as(a0));
95 37356 auto axx = plf::rec[eve::pedantic][invax](ax);
96 37356 auto thresh = axx > plf::dec(plf::sqrt(T(2))); //plf::sqrt_2m1(eve::as(x));
97 37356 auto axxx = plf::if_else(thresh, plf::oneminus(axx) / inc(axx), axx); // all lanes are less than sqrt(2)-1)
98 37356 T r(eve::atan(plf::hi(axxx)));
99 37356 auto t = plf::tan[quarter_circle](r);
100 37356 r -= (t - axxx) * plf::rec(plf::inc(plf::sqr(t)));
101 if constexpr (dimension_v<T> == 2)
102 {
103 2784 r = if_else(thresh && invax, pio_4(eve::as(a0)) + r, r);
104 2784 r = if_else(thresh && !invax, pio_4(eve::as(a0)) - r, r);
105 2784 r = if_else(!thresh && invax, pio_2(eve::as(a0)) - r, r);
106 2784 r = if_else(a0pos, r, -r);
107 2784 return r;
108 }
109 else if constexpr (dimension_v<T> == 3)
110 {
111 34572 t = plf::tan[quarter_circle](r);
112 34572 r -= (t - axxx) * plf::rec(plf::inc(plf::sqr(t)));
113 34572 r = if_else(thresh && invax, pio_4(eve::as(a0)) + r, r);
114 34572 r = if_else(thresh && !invax, pio_4(eve::as(a0)) - r, r);
115 34572 r = if_else(!thresh && invax, pio_2(eve::as(a0)) - r, r);
116 34572 r = if_else(a0pos, r, -r);
117 34572 return r;
118 }
119 }
120 }
121 constexpr auto atand = plf::atan[eve::deg];
122 constexpr auto atanpi = plf::atan[eve::radpi];
123
124 }
125