| 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/constants/log_10.hpp> | ||
| 15 | |||
| 16 | namespace plf | ||
| 17 | { | ||
| 18 | |||
| 19 | template<typename Options> | ||
| 20 | struct pow_abs_t : plf::elementwise_callable<pow_abs_t, eve::pow_abs_t, Options, raw_option, pedantic_option> | ||
| 21 | { | ||
| 22 | template<concepts::polyfloat_like Z1, concepts::polyfloat_like Z2> | ||
| 23 | 612 | POLYFLOAT_ABI constexpr plf::as_polyfloat_like_t<Z1, Z2> operator()(Z1 z1, Z2 z2) const noexcept | |
| 24 | { | ||
| 25 | 612 | return POLYFLOAT_CALL(z1, z2); | |
| 26 | } | ||
| 27 | |||
| 28 | 604 | POLYFLOAT_CALLABLE_OBJECT(pow_abs_t, pow_abs_); | |
| 29 | }; | ||
| 30 | //====================================================================================================================== | ||
| 31 | //! @addtogroup math | ||
| 32 | //! @{ | ||
| 33 | //! @var pow_abs | ||
| 34 | //! @brief return \f$|x|^y\f$. | ||
| 35 | //! | ||
| 36 | //! @groupheader{Header file} | ||
| 37 | //! | ||
| 38 | //! @code | ||
| 39 | //! #include <polyfloat/core.hpp> | ||
| 40 | //! @endcode | ||
| 41 | //! | ||
| 42 | //! @groupheader{Callable Signatures} | ||
| 43 | //! | ||
| 44 | //! @code | ||
| 45 | //! namespace polyfloat | ||
| 46 | //! { | ||
| 47 | //! template<polyfloat::concepts::polyfloat_like T> constpow_absr auto pow_abs(T x, T x) noexcept; | ||
| 48 | //! } | ||
| 49 | //! @endcode | ||
| 50 | //! | ||
| 51 | //! **Parameters** | ||
| 52 | //! | ||
| 53 | //! * `z`: Value to process. | ||
| 54 | //! | ||
| 55 | //! **Return value** | ||
| 56 | //! | ||
| 57 | //! Returns \f$|x|^y\f$. | ||
| 58 | //! | ||
| 59 | //! @groupheader{Example} | ||
| 60 | //! | ||
| 61 | //! @godbolt{doc/math/pow_abs.cpp} | ||
| 62 | //====================================================================================================================== | ||
| 63 | |||
| 64 | inline constexpr auto pow_abs = eve::functor<pow_abs_t>; | ||
| 65 | //====================================================================================================================== | ||
| 66 | //! @} | ||
| 67 | //====================================================================================================================== | ||
| 68 | } | ||
| 69 | |||
| 70 | namespace plf::_ | ||
| 71 | { | ||
| 72 | |||
| 73 | template<typename T, typename U, eve::callable_options O> | ||
| 74 | 604 | constexpr auto pow_abs_(POLYFLOAT_DELAY(), O const& o, T a, U b) noexcept | |
| 75 | { | ||
| 76 | using r_t = as_polyfloat_like_t<T, U>; | ||
| 77 | using e_t = eve::element_type_t<r_t>; | ||
| 78 | using u_t = eve::underlying_type_t<r_t>; | ||
| 79 | 612 | auto cvt = [](auto a) { return plf::convert(a, eve::as<e_t>()); }; | |
| 80 | 604 | auto x = cvt(a); | |
| 81 | 604 | auto y = cvt(b); | |
| 82 | |||
| 83 | 604 | auto iseqzx = plf::is_eqz(x); | |
| 84 | 604 | auto ylt0 = y < plf::zero(as(y)); | |
| 85 | 604 | auto ax = plf::abs(x); | |
| 86 | 604 | auto ax_is1 = plf::is_unit(ax); | |
| 87 | 604 | auto const largelimit = (sizeof(u_t) == 4 ? 31 : 63); | |
| 88 | 1172 | auto [yf, yi] = plf::modf(plf::abs(y)); | |
| 89 | 604 | auto test = yf > r_t(0.5); | |
| 90 | 604 | yf = dec[test](yf); | |
| 91 | 604 | auto z = plf::exp[o](yf * plf::log[o](ax)); | |
| 92 | 604 | yi = inc[test](yi); | |
| 93 | 604 | yi = if_else(ax_is1, eve::one, yi); | |
| 94 | 604 | auto large = (yi > r_t(largelimit)); | |
| 95 | 604 | yi = if_else(large, eve::one, yi); | |
| 96 | |||
| 97 | 306 | auto russian = [](auto base, auto rexpo) { | |
| 98 | 290 | r_t result(1); | |
| 99 | 306 | auto expo(rexpo); | |
| 100 |
16/16✓ Branch 2 taken 116 times.
✓ Branch 3 taken 78 times.
✓ Branch 6 taken 104 times.
✓ Branch 7 taken 70 times.
✓ Branch 10 taken 104 times.
✓ Branch 11 taken 70 times.
✓ Branch 14 taken 108 times.
✓ Branch 15 taken 72 times.
✓ Branch 18 taken 6 times.
✓ Branch 19 taken 4 times.
✓ Branch 22 taken 6 times.
✓ Branch 23 taken 4 times.
✓ Branch 26 taken 6 times.
✓ Branch 27 taken 4 times.
✓ Branch 30 taken 6 times.
✓ Branch 31 taken 4 times.
|
762 | while (eve::any(is_nez(expo))) |
| 101 | { | ||
| 102 | 456 | result *= if_else(is_odd(expo), base, eve::one); | |
| 103 | 456 | expo = eve::trunc(expo / 2); | |
| 104 | 456 | base = sqr(base); | |
| 105 | } | ||
| 106 | 306 | return result; | |
| 107 | }; | ||
| 108 | 604 | if constexpr (!O::contains(raw)) yi = if_else(is_not_finite(yi), eve::zero, yi); | |
| 109 | 604 | z *= russian(ax, hi(yi)); | |
| 110 | 604 | z = if_else(large, if_else(ax < one(as(x)), zero, inf(as(x))), z); | |
| 111 | 604 | z = if_else(iseqzx && ylt0, zero, z); | |
| 112 | 604 | z = if_else(is_infinite(ax), inf(as(x)), z); | |
| 113 | 604 | z = if_else(ylt0, plf::rec(z), z); | |
| 114 | 604 | z = if_else(ax_is1 || is_eqz(y), one, z); | |
| 115 | 604 | z = if_else(iseqzx && is_gtz(y), zero, z); | |
| 116 | 604 | z = if_else(is_nan(x) && is_nan(y), allbits, z); | |
| 117 | 604 | return z; | |
| 118 | } | ||
| 119 | } | ||
| 120 |