// Copyright 2023 - 2024 Matt Borland // Copyright 2023 - 2024 Christopher Kormanyos // Distributed under the Boost Software License, Version 1.0. // https://www.boost.org/LICENSE_1_0.txt #ifndef BOOST_DECIMAL_DETAIL_CMATH_COS_HPP #define BOOST_DECIMAL_DETAIL_CMATH_COS_HPP #include #include #include #include #include #include #include #include #include #ifndef BOOST_DECIMAL_BUILD_MODULE #include #include #endif namespace boost { namespace decimal { namespace detail { template constexpr auto cos_impl(const T x) noexcept BOOST_DECIMAL_REQUIRES(detail::is_decimal_floating_point_v, T) { T result { }; #ifndef BOOST_DECIMAL_FAST_MATH const auto fpc = fpclassify(x); // First check non-finite values and small angles if ((fpc == FP_INFINITE) || (fpc == FP_NAN)) { result = x; } else #endif if (signbit(x)) { result = cos(-x); } else { if (x > std::numeric_limits::epsilon()) { // Perform argument reduction and subsequent scaling of the result. // Given x = k * (pi/2) + r, compute n = (k % 4). // | n | sin(x) | cos(x) | sin(x)/cos(x) | // |----------------------------------------| // | 0 | sin(r) | cos(r) | sin(r)/cos(r) | // | 1 | cos(r) | -sin(r) | -cos(r)/sin(r) | // | 2 | -sin(r) | -cos(r) | sin(r)/cos(r) | // | 3 | -cos(r) | sin(r) | -cos(r)/sin(r) | const T two_x = x * 2; const auto k = static_cast(two_x / numbers::pi_v); const auto n = k % static_cast(UINT8_C(4)); const T two_r { two_x - (numbers::pi_v * k) }; T r { two_r / 2 }; constexpr T half { 5, -1 }; const bool do_scaling { r > half }; if(do_scaling) { // Reduce the argument with factors of three. r /= static_cast(UINT8_C(3)); } switch(n) { case static_cast(UINT8_C(1)): case static_cast(UINT8_C(3)): result = detail::sin_series_expansion(r); break; case static_cast(UINT8_C(0)): case static_cast(UINT8_C(2)): default: result = detail::cos_series_expansion(r); break; } if(do_scaling) { result *= (((result * result) * static_cast(UINT8_C(4))) - static_cast(UINT8_C(3))); } if(signbit(result)) { result = -result; } const auto b_neg = ((n == static_cast(UINT8_C(1))) || (n == static_cast(UINT8_C(2)))); if(b_neg) { result = -result; } } else { constexpr T one { 1 }; result = one; } } return result; } } // namespace detail BOOST_DECIMAL_EXPORT template constexpr auto cos(const T x) noexcept BOOST_DECIMAL_REQUIRES(detail::is_decimal_floating_point_v, T) { using evaluation_type = detail::evaluation_type_t; return static_cast(detail::cos_impl(static_cast(x))); } } // namespace decimal } // namespace boost #endif // BOOST_DECIMAL_DETAIL_CMATH_COS_HPP