GCC Code Coverage Report


Directory: include/polyfloat/
File: include/polyfloat/module/math/atan2.hpp
Date: 2026-11-09 15:28:50
Exec Total Coverage
Lines: 20 20 100.0%
Functions: 57 57 100.0%
Branches: 1 2 50.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 #include <polyfloat/module/math/atan.hpp>
16 #include <polyfloat/module/math/radindeg.hpp>
17 #include <polyfloat/module/math/radinpi.hpp>
18
19 namespace plf
20 {
21
22 template<typename Options>
23 struct atan2_t : plf::elementwise_callable<atan2_t,
24 eve::atan2_t,
25 Options,
26 raw_option,
27 pedantic_option,
28 eve::rad_option,
29 eve::radpi_option,
30 eve::deg_option>
31 {
32 template<concepts::polyfloat_like Z0, concepts::polyfloat_like Z1>
33 20758 POLYFLOAT_ABI constexpr plf::as_polyfloat_like_t<Z0, Z1> operator()(Z0 z0, Z1 z1) const noexcept
34 {
35 20758 return POLYFLOAT_CALL(z0, z1);
36 }
37
38 20748 POLYFLOAT_CALLABLE_OBJECT(atan2_t, atan2_);
39 };
40 //======================================================================================================================
41 //! @addtogroup math
42 //! @{
43 //! @var atan2
44 //! @brief return the arctangent value.
45 //!
46 //! @groupheader{Header file}
47 //!
48 //! @code
49 //! #include <polyfloat/core.hpp>
50 //! @endcode
51 //!
52 //! @groupheader{Callable Signatures}
53 //!
54 //! @code
55 //! namespace polyfloat
56 //! {
57 //! template<polyfloat::concepts::polyfloat_like T> constexpr auto atan2(T z) noexcept; //1
58 //! template<polyfloat::concepts::polyfloat_like T> constexpr auto atan2[pedantic](T z) noexcept; //2
59 //! }
60 //! @endcode
61 //!
62 //! **Parameters**
63 //!
64 //! * `x, y`: Value to process.
65 //!
66 //! **Return value**
67 //!
68 //! 1. The arc tangent of \f$\frac{y}x\f$ in the radian range \f$[-\pi , +\pi]\f$ (1.a) , is returned.
69 //! (converted in degrees (1.b) or in \f$[\pi\f$ multiples (1.c))
70 //! For 1.a The **IEEE** limiting values are almost all satisfied :
71 //!
72 //! * If `x` and `y` are both zero or infinites, Nan is returned (this is not standard conforming)
73 //! * If `y` is \f$\pm0\f$ and `x` is strictly negative or \f$-0\f$, \f$\pm\pi\f$ is returned
74 //! * If `y` is \f$\pm0\f$ and `x` is strictly positive or \f$+0\f$, \f$\pm0\f$ is returned
75 //! * If `y` is \f$\pm\infty\f$ and `x` is finite, \f$\pm\frac\pi2\f$ is returned
76 //! * If `x` is \f$\pm0\f$ and `y` is strictly negative, \f$-\frac\pi2\f$ is returned
77 //! * If `x` is \f$\pm0\f$ and `y` is strictly positive, \f$+\frac\pi2\f$ is returned
78 //! * If `x` is \f$-\infty\f$ and `y` is finite and positive, \f$+\pi\f$ is returned
79 //! * If `x` is \f$-\infty\f$ and `y` is finite and negative, \f$-\pi\f$ is returned
80 //! * If `x` is \f$+\infty\f$ and `y` is finite and positive, \f$+0\f$ is returned
81 //! * If `x` is \f$+\infty\f$ and `y` is finite and negative, \f$-0\f$ is returned
82 //! * If either `x` is Nan or `y` is Nan, Nan is returned
83 //!
84 //! The call will return a NaN if `x` and `y` are both either null or infinite: this result is
85 //! not **IEEE** conformant, but allows to simplify (and speed up) the implementation.
86 //! In all other cases, the result is standard conformant. And the converted equivalent are returned with the other units.
87 //! 2. Same as 1, except that all **IEEE** limiting values are satisfied :
88 //! * If `y` is \f$\pm\infty\f$ and `x` is \f$-\infty\f$, \f$\pm\frac{3\pi}4\f$ is returned
89 //! * If `y` is \f$\pm\infty\f$ and `x` is \f$+\infty\f$, \f$\pm\frac{\pi}4\f$ is returned
90 //! * If `x` is \f$\pm0\f$ and `y` is \f$\pm-0\f$, \f$-\frac\pi2\f$ is returned
91 //! * If `x` is \f$\pm0\f$ and `y` is \f$\pm+0\f$, \f$+\frac\pi2\f$ is returned
92 //!
93 //! @groupheader{Example}
94 //!
95 //! @godbolt{doc/math/atan2.cpp}
96 //======================================================================================================================
97
98 inline constexpr auto atan2 = eve::functor<atan2_t>;
99 //======================================================================================================================
100 //! @}
101 //======================================================================================================================
102 }
103
104 namespace plf::_
105 {
106 template<typename T, typename U, eve::callable_options O>
107 20748 constexpr auto atan2_(POLYFLOAT_DELAY(), O const& o, T a0, U a1) noexcept
108 {
109 if constexpr (O::contains(eve::rad)) return atan2[o.drop(rad)](a0, a1);
110 else if constexpr (O::contains(eve::deg)) return radindeg(atan2[o.drop(eve::deg)](a0, a1));
111 else if constexpr (O::contains(eve::radpi)) return radinpi(atan2[o.drop(eve::radpi)](a0, a1));
112 else
113 {
114 using r_t = plf::as_polyfloat_like_t<T, U>;
115 using elt_t = eve::element_type_t<r_t>;
116 20752 auto cvt = [](auto a) { return plf::convert(a, eve::as<elt_t>()); };
117 20748 r_t a00 = cvt(a0);
118 20748 r_t a10 = cvt(a1);
119 if constexpr (O::contains(pedantic))
120 {
121 if constexpr (eve::scalar_value<r_t> && eve::platform::supports_nans)
122 {
123
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 32 times.
64 if (plf::is_unordered(a00, a10)) return plf::nan(eve::as(a00));
124 }
125 if constexpr (eve::platform::supports_infinites)
126 {
127 64 auto test1 = plf::is_infinite(a00) && plf::is_infinite(a10);
128 64 a00 = plf::if_else(test1, plf::copysign(one(eve::as(a00)), a00), a00);
129 64 a10 = plf::if_else(test1, plf::copysign(one(eve::as(a00)), a10), a10);
130 }
131 64 auto q = plf::abs(a00 / a10);
132 64 r_t z = plf::atan(q);
133 64 r_t sgn = signnz(a00);
134 64 z = plf::if_else(plf::is_positive(a10), z, plf::pi(eve::as(a0)) - z) * sgn;
135 64 z = plf::if_else(plf::is_eqz(a00), plf::if_else(plf::is_negative(a10), plf::pi(eve::as(a00)) * sgn, plf::zero),
136 z);
137 64 if constexpr (eve::platform::supports_nans) return plf::if_else(is_unordered(a00, a10), plf::allbits, z);
138 else return z;
139 }
140 else
141 {
142 20684 auto q = plf::abs(a00 / a10);
143 20684 auto z = plf::atan(q);
144 20684 return if_else(is_positive(a10), z, (pi(eve::as(a00)) - z)) * signnz(a00);
145 }
146 }
147 }
148 constexpr auto atan2d = plf::atan2[eve::deg];
149 constexpr auto atan2pi = plf::atan2[eve::radpi];
150
151 }
152