| 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 |