// Copyright (C) 2026 Kiyotsugu Arai // SPDX-License-Identifier: LGPL-3.0-or-later // special_common.hpp // Common foundation for special-function templates // Provides type-classification concepts and shared utilities. #ifndef SANGI_SPECIAL_COMMON_HPP #define SANGI_SPECIAL_COMMON_HPP #include #include #include #include #include #include #include namespace sangi { // ================================================================ // Type-classification concepts // ================================================================ /// Whether the type is sangi::Float template concept IsSangiFloat = std::same_as, Float>; /// Native floating-point type (float, double, long double) template concept IsNativeFloat = std::floating_point; /// Whether the type is sangi::Complex template struct is_sangi_complex_type : std::false_type {}; template struct is_sangi_complex_type> : std::true_type {}; template inline constexpr bool is_sangi_complex_type_v = is_sangi_complex_type::value; template concept IsSangiComplex = is_sangi_complex_type_v>; /// Get the inner scalar type of Complex template struct complex_value_type { using type = T; }; template struct complex_value_type> { using type = U; }; template using complex_value_type_t = typename complex_value_type::type; /// Scalar types usable with special functions (float, double, long double, Float) template concept SpecialFunctionScalar = IsNativeFloat || IsSangiFloat; // ================================================================ // Special-function utilities (with Complex support) // ================================================================ namespace special { namespace detail { /// Return the machine epsilon appropriate for the type template [[nodiscard]] R getEpsilon() { if constexpr (IsSangiFloat) return Float::epsilon(Float::defaultPrecision()); else return std::numeric_limits::epsilon(); } template [[nodiscard]] R getEpsilon(int precision) { if constexpr (IsSangiFloat) return Float::epsilon(precision); else return std::numeric_limits::epsilon(); } /// π template [[nodiscard]] R getPi() { if constexpr (IsSangiFloat) return Float::pi(Float::defaultPrecision()); else return std::numbers::template pi_v; } template [[nodiscard]] R getPi(int precision) { if constexpr (IsSangiFloat) return Float::pi(precision); else return std::numbers::template pi_v; } /// Euler-Mascheroni constant γ template [[nodiscard]] R getEulerGamma() { if constexpr (IsSangiFloat) return Float::euler(Float::defaultPrecision()); else return static_cast(0.5772156649015328606065120900824024310421593359L); } /// ln(2) template [[nodiscard]] R getLn2() { if constexpr (IsSangiFloat) return log(Float(2), Float::defaultPrecision()); else return std::numbers::template ln2_v; } /// NaN template [[nodiscard]] R getNaN() { if constexpr (IsSangiFloat) return Float::nan(); else return std::numeric_limits::quiet_NaN(); } /// +Infinity template [[nodiscard]] R getInfinity() { if constexpr (IsSangiFloat) return Float::positiveInfinity(); else return std::numeric_limits::infinity(); } } // namespace detail } // namespace special } // namespace sangi #endif // SANGI_SPECIAL_COMMON_HPP