From 28536b312ab2a95c990c8b990ca0a4aef7868c9e Mon Sep 17 00:00:00 2001 From: Ian Date: Sun, 1 Sep 2024 00:43:24 -0400 Subject: [PATCH] Setup initial work for pow implementation --- ccmath_core_headers.cmake | 8 +- ccmath_internal_headers.cmake | 91 +++--- .../math/generic/func/power/pow_gen.hpp | 56 +--- .../math/generic/func/power/pow_impl.hpp | 32 ++ .../math/generic/func/power/powf_impl.hpp | 32 ++ .../math/runtime/func/power/pow_rt.hpp | 73 +++++ .../math/runtime/simd/func/impl/avx/pow.hpp | 35 +++ .../math/runtime/simd/func/impl/avx2/pow.hpp | 36 +++ .../runtime/simd/func/impl/avx512/pow.hpp | 35 +++ .../math/runtime/simd/func/impl/neon/pow.hpp | 33 ++ .../runtime/simd/func/impl/scalar/pow.hpp | 23 ++ .../math/runtime/simd/func/impl/sse2/pow.hpp | 33 ++ .../math/runtime/simd/func/impl/sse3/pow.hpp | 33 ++ .../math/runtime/simd/func/impl/sse4/pow.hpp | 33 ++ .../math/runtime/simd/func/impl/ssse3/pow.hpp | 33 ++ .../simd/func/impl/vector_size/pow.hpp | 38 +++ .../internal/math/runtime/simd/func/pow.hpp | 14 + include/ccmath/math/power/impl/pow_impl.hpp | 294 ------------------ include/ccmath/math/power/pow.hpp | 55 +--- 19 files changed, 555 insertions(+), 432 deletions(-) create mode 100644 include/ccmath/internal/math/generic/func/power/pow_impl.hpp create mode 100644 include/ccmath/internal/math/generic/func/power/powf_impl.hpp create mode 100644 include/ccmath/internal/math/runtime/func/power/pow_rt.hpp create mode 100644 include/ccmath/internal/math/runtime/simd/func/impl/avx/pow.hpp create mode 100644 include/ccmath/internal/math/runtime/simd/func/impl/avx2/pow.hpp create mode 100644 include/ccmath/internal/math/runtime/simd/func/impl/avx512/pow.hpp create mode 100644 include/ccmath/internal/math/runtime/simd/func/impl/neon/pow.hpp create mode 100644 include/ccmath/internal/math/runtime/simd/func/impl/scalar/pow.hpp create mode 100644 include/ccmath/internal/math/runtime/simd/func/impl/sse2/pow.hpp create mode 100644 include/ccmath/internal/math/runtime/simd/func/impl/sse3/pow.hpp create mode 100644 include/ccmath/internal/math/runtime/simd/func/impl/sse4/pow.hpp create mode 100644 include/ccmath/internal/math/runtime/simd/func/impl/ssse3/pow.hpp create mode 100644 include/ccmath/internal/math/runtime/simd/func/impl/vector_size/pow.hpp create mode 100644 include/ccmath/internal/math/runtime/simd/func/pow.hpp delete mode 100644 include/ccmath/math/power/impl/pow_impl.hpp diff --git a/ccmath_core_headers.cmake b/ccmath_core_headers.cmake index 1422a95..a5c8fb0 100644 --- a/ccmath_core_headers.cmake +++ b/ccmath_core_headers.cmake @@ -7,6 +7,7 @@ # Math Section ############################################################################## +# TODO: Remove all impls from here into the generic headers. ### Basic/Impl headers ########################################## @@ -152,13 +153,6 @@ set(ccmath_detail_nearest_headers ${CMAKE_CURRENT_SOURCE_DIR}/include/ccmath/math/nearest/trunc.hpp ) -### Power/Impl headers - TODO: Remove this an instead use the generic power headers -########################################## -set(ccmath_math_power_impl_headers - ${CMAKE_CURRENT_SOURCE_DIR}/include/ccmath/math/power/impl/pow_impl.hpp -) - - ####################################### ## Power headers diff --git a/ccmath_internal_headers.cmake b/ccmath_internal_headers.cmake index 46a81a0..6e55336 100644 --- a/ccmath_internal_headers.cmake +++ b/ccmath_internal_headers.cmake @@ -2,6 +2,10 @@ # Internal Section ############################################################################## +########################################## +### Config Section +########################################## + ### Config/Arch/Targets headers ########################################## set(ccmath_internal_config_arch_targets_headers @@ -56,7 +60,12 @@ set(ccmath_internal_config_headers ) -#### Math/Generic Modules #### +########################################## +### Math Section +########################################## + +### Generic Module +########################################## ### Math/Generic/Func/Basic headers ########################################## @@ -75,9 +84,13 @@ set(ccmath_internal_math_generic_func_basic_headers ### Math/Generic/Func/Expo headers ########################################## set(ccmath_internal_math_generic_func_expo_headers + ${CMAKE_CURRENT_SOURCE_DIR}/include/ccmath/internal/math/generic/func/expo/exp2_gen.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/include/ccmath/internal/math/generic/func/expo/exp_gen.hpp ${CMAKE_CURRENT_SOURCE_DIR}/include/ccmath/internal/math/generic/func/expo/expm1_gen.hpp ${CMAKE_CURRENT_SOURCE_DIR}/include/ccmath/internal/math/generic/func/expo/log1p_gen.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/include/ccmath/internal/math/generic/func/expo/log2_gen.hpp ${CMAKE_CURRENT_SOURCE_DIR}/include/ccmath/internal/math/generic/func/expo/log10_gen.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/include/ccmath/internal/math/generic/func/expo/log_gen.hpp ) @@ -129,37 +142,39 @@ set(ccmath_internal_math_generic_func_nearest_headers ### Math/Generic/Func/Power headers ########################################## set(ccmath_internal_math_generic_func_power_headers - ${CMAKE_CURRENT_SOURCE_DIR}/include/ccmath/internal/math/generic/func/nearest/cbrt_gen.hpp - ${CMAKE_CURRENT_SOURCE_DIR}/include/ccmath/internal/math/generic/func/nearest/hypot_gen.hpp - ${CMAKE_CURRENT_SOURCE_DIR}/include/ccmath/internal/math/generic/func/nearest/pow_gen.hpp - ${CMAKE_CURRENT_SOURCE_DIR}/include/ccmath/internal/math/generic/func/nearest/sqrt_gen.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/include/ccmath/internal/math/generic/func/power/cbrt_gen.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/include/ccmath/internal/math/generic/func/power/hypot_gen.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/include/ccmath/internal/math/generic/func/power/pow_gen.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/include/ccmath/internal/math/generic/func/power/pow_impl.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/include/ccmath/internal/math/generic/func/power/powf_impl.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/include/ccmath/internal/math/generic/func/power/sqrt_gen.hpp ) ### Math/Generic/Func/Special headers ########################################## set(ccmath_internal_math_generic_func_special_headers - ${CMAKE_CURRENT_SOURCE_DIR}/include/ccmath/internal/math/generic/func/special/assoc_laguerre.hpp - ${CMAKE_CURRENT_SOURCE_DIR}/include/ccmath/internal/math/generic/func/special/assoc_legendre.hpp - ${CMAKE_CURRENT_SOURCE_DIR}/include/ccmath/internal/math/generic/func/special/beta.hpp - ${CMAKE_CURRENT_SOURCE_DIR}/include/ccmath/internal/math/generic/func/special/comp_ellint_1.hpp - ${CMAKE_CURRENT_SOURCE_DIR}/include/ccmath/internal/math/generic/func/special/comp_ellint_2.hpp - ${CMAKE_CURRENT_SOURCE_DIR}/include/ccmath/internal/math/generic/func/special/comp_ellint_3.hpp - ${CMAKE_CURRENT_SOURCE_DIR}/include/ccmath/internal/math/generic/func/special/cyl_bessel_i.hpp - ${CMAKE_CURRENT_SOURCE_DIR}/include/ccmath/internal/math/generic/func/special/cyl_bessel_j.hpp - ${CMAKE_CURRENT_SOURCE_DIR}/include/ccmath/internal/math/generic/func/special/cyl_bessel_k.hpp - ${CMAKE_CURRENT_SOURCE_DIR}/include/ccmath/internal/math/generic/func/special/cyl_neumann.hpp - ${CMAKE_CURRENT_SOURCE_DIR}/include/ccmath/internal/math/generic/func/special/ellint_1.hpp - ${CMAKE_CURRENT_SOURCE_DIR}/include/ccmath/internal/math/generic/func/special/ellint_2.hpp - ${CMAKE_CURRENT_SOURCE_DIR}/include/ccmath/internal/math/generic/func/special/ellint_3.hpp - ${CMAKE_CURRENT_SOURCE_DIR}/include/ccmath/internal/math/generic/func/special/expint.hpp - ${CMAKE_CURRENT_SOURCE_DIR}/include/ccmath/internal/math/generic/func/special/hermite.hpp - ${CMAKE_CURRENT_SOURCE_DIR}/include/ccmath/internal/math/generic/func/special/laguerre.hpp - ${CMAKE_CURRENT_SOURCE_DIR}/include/ccmath/internal/math/generic/func/special/legendre.hpp - ${CMAKE_CURRENT_SOURCE_DIR}/include/ccmath/internal/math/generic/func/special/riemann_zeta.hpp - ${CMAKE_CURRENT_SOURCE_DIR}/include/ccmath/internal/math/generic/func/special/sph_bessel.hpp - ${CMAKE_CURRENT_SOURCE_DIR}/include/ccmath/internal/math/generic/func/special/sph_legendre.hpp - ${CMAKE_CURRENT_SOURCE_DIR}/include/ccmath/internal/math/generic/func/special/sph_neumann.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/include/ccmath/internal/math/generic/func/special/assoc_laguerre_gen.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/include/ccmath/internal/math/generic/func/special/assoc_legendre_gen.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/include/ccmath/internal/math/generic/func/special/beta_gen.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/include/ccmath/internal/math/generic/func/special/comp_ellint_1_gen.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/include/ccmath/internal/math/generic/func/special/comp_ellint_2_gen.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/include/ccmath/internal/math/generic/func/special/comp_ellint_3_gen.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/include/ccmath/internal/math/generic/func/special/cyl_bessel_i_gen.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/include/ccmath/internal/math/generic/func/special/cyl_bessel_j_gen.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/include/ccmath/internal/math/generic/func/special/cyl_bessel_k_gen.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/include/ccmath/internal/math/generic/func/special/cyl_neumann_gen.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/include/ccmath/internal/math/generic/func/special/ellint_1_gen.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/include/ccmath/internal/math/generic/func/special/ellint_2_gen.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/include/ccmath/internal/math/generic/func/special/ellint_3_gen.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/include/ccmath/internal/math/generic/func/special/expint_gen.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/include/ccmath/internal/math/generic/func/special/hermite_gen.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/include/ccmath/internal/math/generic/func/special/laguerre_gen.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/include/ccmath/internal/math/generic/func/special/legendre_gen.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/include/ccmath/internal/math/generic/func/special/riemann_zeta_gen.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/include/ccmath/internal/math/generic/func/special/sph_bessel_gen.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/include/ccmath/internal/math/generic/func/special/sph_legendre_gen.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/include/ccmath/internal/math/generic/func/special/sph_neumann_gen.hpp ) @@ -197,18 +212,17 @@ set(ccmath_internal_math_generic_headers ) - -### Math/Runtime/func headers +### Math/Runtime/Func/Power headers ########################################## -set(ccmath_internal_math_runtime_func_headers - ${ccmath_internal_math_runtime_func_power_headers} +set(ccmath_internal_math_runtime_func_power_headers + ${CMAKE_CURRENT_SOURCE_DIR}/include/ccmath/internal/math/runtime/func/power/pow_rt.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/include/ccmath/internal/math/runtime/func/power/sqrt_rt.hpp ) - -### Math/Runtime headers +### Math/Runtime/Func headers ########################################## -set(ccmath_internal_math_runtime_headers - ${ccmath_internal_math_runtime_func_headers} +set(ccmath_internal_math_runtime_func_headers + ${ccmath_internal_math_runtime_func_power_headers} ) @@ -297,6 +311,7 @@ set(ccmath_internal_math_runtime_simd_func_headers ${ccmath_internal_math_runtime_simd_func_impl_vector_size_headers} ${CMAKE_CURRENT_SOURCE_DIR}/include/ccmath/internal/math/runtime/simd/func/sqrt.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/include/ccmath/internal/math/runtime/simd/func/pow.hpp ) @@ -327,7 +342,8 @@ set(ccmath_internal_math_runtime_simd_headers ${CMAKE_CURRENT_SOURCE_DIR}/include/ccmath/internal/math/runtime/simd/simd.hpp ) - +### Math/Runtime headers +########################################## set(ccmath_internal_math_runtime_headers ${ccmath_internal_math_runtime_func_headers} ${ccmath_internal_math_runtime_simd_headers} @@ -480,11 +496,10 @@ set(ccmath_internal_types_headers set(ccmath_internal_headers ${ccmath_internal_config_headers} - ${ccmath_internal_generic_headers} + ${ccmath_internal_math_headers} ${ccmath_internal_predef_headers} - ${ccmath_internal_math_runtime_headers} ${ccmath_internal_support_headers} ${ccmath_internal_types_headers} ${CMAKE_CURRENT_SOURCE_DIR}/include/ccmath/internal/setup.hpp -) \ No newline at end of file +) diff --git a/include/ccmath/internal/math/generic/func/power/pow_gen.hpp b/include/ccmath/internal/math/generic/func/power/pow_gen.hpp index fc38e65..3a2d975 100644 --- a/include/ccmath/internal/math/generic/func/power/pow_gen.hpp +++ b/include/ccmath/internal/math/generic/func/power/pow_gen.hpp @@ -10,59 +10,19 @@ #pragma once -#include - -#include "ccmath/math/exponential/exp2.hpp" -#include "ccmath/math/exponential/log2.hpp" - -#include "ccmath/math/power/impl/pow_impl.hpp" +#include "ccmath/internal/math/generic/func/power/pow_impl.hpp" +#include "ccmath/internal/math/generic/func/power/powf_impl.hpp" +#include -namespace ccm +namespace ccm::gen { - namespace internal::impl - { - template && std::is_unsigned_v, bool> = true> - constexpr T pow_expo_by_sqr(T base, T exp) noexcept - { - // Handle common cases - if (exp == 0) { return 1; } // Anything to the power of 0 is 1 - if (exp == 1) { return base; } // Anything to the power of 1 is itself - if (exp == 2) { return base * base; } // Anything to the power of 2 is itself squared - if (base == 0) { return 0; } // 0 to any power is 0 - if (base == 1) { return 1; } // 1 to any power is 1 - - // If the base is 2, we can use the bit shift operator to calculate the power. - if (base == 2) { return 1 << exp; } - - // This is pretty fast with smaller numbers, but is slower than the standard when dealing with large numbers. - // TODO: Find a way to optimize this for larger numbers. - T result = 1; - for (;;) - { - if (exp & 1) { result *= base; } - exp >>= 1; - if (!exp) { break; } - base *= base; - } - - return result; - } - - template , bool> = true> - constexpr T pow_generic(T base, T exp) noexcept - { - // This should work on all x86 platforms but may not work with other architectures. - // For now this is more of a hold over till I have time to implement a better generic version. - return ccm::exp2(exp * ccm::log2(base)); - } - } // namespace internal::impl - template - constexpr T pow(T base, T exp) noexcept + constexpr T pow_gen(T base, T exp) noexcept { - if constexpr (std::is_integral_v && std::is_unsigned_v) { return internal::impl::pow_expo_by_sqr(base, exp); } - return internal::impl::pow_generic(base, exp); + //if constexpr (std::is + + return 0; } } // namespace ccm diff --git a/include/ccmath/internal/math/generic/func/power/pow_impl.hpp b/include/ccmath/internal/math/generic/func/power/pow_impl.hpp new file mode 100644 index 0000000..0a883c4 --- /dev/null +++ b/include/ccmath/internal/math/generic/func/power/pow_impl.hpp @@ -0,0 +1,32 @@ +/* +* Copyright (c) Ian Pike + * Copyright (c) CCMath contributors + * + * CCMath is provided under the Apache-2.0 License WITH LLVM-exception. + * See LICENSE for more information. + * + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#pragma once + +#include + +namespace ccm::gen::impl +{ + namespace internal::impl + { + template + constexpr T pow_impl(T base, T exp) noexcept + { + return 0; + } + } + + template + constexpr T pow_impl(T base, T exp) noexcept + { + return internal::impl::pow_impl(base, exp); + } + +} // namespace ccm diff --git a/include/ccmath/internal/math/generic/func/power/powf_impl.hpp b/include/ccmath/internal/math/generic/func/power/powf_impl.hpp new file mode 100644 index 0000000..71d51bd --- /dev/null +++ b/include/ccmath/internal/math/generic/func/power/powf_impl.hpp @@ -0,0 +1,32 @@ +/* + * Copyright (c) Ian Pike + * Copyright (c) CCMath contributors + * + * CCMath is provided under the Apache-2.0 License WITH LLVM-exception. + * See LICENSE for more information. + * + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#pragma once + +#include + +namespace ccm::gen::impl +{ + namespace internal::impl + { + template + constexpr T powf_impl(T base, T exp) noexcept + { + return 0; + } + } + + template + constexpr T powf_impl(T base, T exp) noexcept + { + return internal::impl::powf_impl(base, exp); + } + +} // namespace ccm diff --git a/include/ccmath/internal/math/runtime/func/power/pow_rt.hpp b/include/ccmath/internal/math/runtime/func/power/pow_rt.hpp new file mode 100644 index 0000000..b1fab82 --- /dev/null +++ b/include/ccmath/internal/math/runtime/func/power/pow_rt.hpp @@ -0,0 +1,73 @@ +/* + * Copyright (c) Ian Pike + * Copyright (c) CCMath contributors + * + * CCMath is provided under the Apache-2.0 License WITH LLVM-exception. + * See LICENSE for more information. + * + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#pragma once + +#include "ccmath/internal/config/type_support.hpp" +#include "ccmath/internal/math/generic/func/power/pow_gen.hpp" +#include "ccmath/internal/math/runtime/simd/func/sqrt.hpp" +#include "ccmath/internal/support/always_false.hpp" +#include "ccmath/internal/support/bits.hpp" +#include "ccmath/internal/support/fenv/rounding_mode.hpp" +#include "ccmath/internal/support/fp/fp_bits.hpp" +#include "ccmath/internal/support/is_constant_evaluated.hpp" + +#include + +namespace ccm::rt::simd_impl +{ +#if defined(CCM_TYPES_LONG_DOUBLE_IS_FLOAT64) + template , bool> = true> +#else + template && !std::is_same_v, bool> = true> +#endif + [[nodiscard]] inline T pow_simd_impl(T num) noexcept; + +#ifdef CCMATH_HAS_SIMD + #if defined(CCM_TYPES_LONG_DOUBLE_IS_FLOAT64) + template , bool>> + #else + template && !std::is_same_v, bool>> + #endif + [[nodiscard]] inline T pow_simd_impl(T num) noexcept + { + intrin::simd const num_m(num); + intrin::simd const sqrt_m = intrin::sqrt(num_m); + return sqrt_m.convert(); + } +#endif +} // namespace ccm::rt::simd_impl + +namespace ccm::rt +{ + template , bool> = true> + T pow_rt(T num) + { +#if CCM_HAS_BUILTIN(__builtin_pow) || defined(__builtin_pow) // Prefer the builtins if available. + if constexpr (std::is_same_v) { return __builtin_powf(num); } + else if constexpr (std::is_same_v) { return __builtin_pow(num); } + else if constexpr (std::is_same_v) { return __builtin_powl(num); } + else { return static_cast(__builtin_powl(static_cast(num))); } +#elif defined(CCMATH_HAS_SIMD) + // In the unlikely event, the rounding mode is not the default, use the runtime implementation instead. + if (CCM_UNLIKELY(ccm::support::fenv::get_rounding_mode() != FE_TONEAREST)) { return gen::pow_gen(num); } + #if !defined(CCM_TYPES_LONG_DOUBLE_IS_FLOAT64) // If long double is different from double, use the generic implementation instead. + if constexpr (std::is_same_v || std::is_same_v) { return simd_impl::pow_simd_impl(num); } + else { return gen::pow_gen(num); } + #else // If long double is the same as double, we can use the SIMD implementation instead. + if constexpr (std::is_same_v || std::is_same_v) { return simd_impl::sqrt_simd_impl(num); } + else if constexpr (std::is_same_v) { return static_cast(simd_impl::sqrt_simd_impl(static_cast(num))); } + else { return ccm::gen::sqrt_gen(num); } + #endif +#else // If we don't have a builtin or SIMD, use the generic implementation. + return ccm::gen::pow_gen(num); +#endif + } +} // namespace ccm::rt diff --git a/include/ccmath/internal/math/runtime/simd/func/impl/avx/pow.hpp b/include/ccmath/internal/math/runtime/simd/func/impl/avx/pow.hpp new file mode 100644 index 0000000..aff96b1 --- /dev/null +++ b/include/ccmath/internal/math/runtime/simd/func/impl/avx/pow.hpp @@ -0,0 +1,35 @@ +/* + * Copyright (c) Ian Pike + * Copyright (c) CCMath contributors + * + * CCMath is provided under the Apache-2.0 License WITH LLVM-exception. + * See LICENSE for more information. + * + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#pragma once + +#include "ccmath/internal/math/runtime/simd/simd.hpp" + +#ifdef CCMATH_HAS_SIMD + #ifdef CCMATH_HAS_SIMD_AVX +namespace ccm::intrin +{ + + CCM_ALWAYS_INLINE simd sqrt(simd const & a) + { + // NOLINTNEXTLINE(modernize-return-braced-init-list) + return simd(_mm256_sqrt_ps(a.get())); + } + + CCM_ALWAYS_INLINE simd sqrt(simd const & a) + { + // NOLINTNEXTLINE(modernize-return-braced-init-list) + return simd(_mm256_sqrt_pd(a.get())); + } + +} // namespace ccm::intrin + + #endif // CCMATH_HAS_SIMD_AVX +#endif // CCMATH_HAS_SIMD diff --git a/include/ccmath/internal/math/runtime/simd/func/impl/avx2/pow.hpp b/include/ccmath/internal/math/runtime/simd/func/impl/avx2/pow.hpp new file mode 100644 index 0000000..6bcdb78 --- /dev/null +++ b/include/ccmath/internal/math/runtime/simd/func/impl/avx2/pow.hpp @@ -0,0 +1,36 @@ +/* + * Copyright (c) Ian Pike + * Copyright (c) CCMath contributors + * + * CCMath is provided under the Apache-2.0 License WITH LLVM-exception. + * See LICENSE for more information. + * + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#pragma once + +#include "ccmath/internal/math/runtime/simd/simd.hpp" + +#ifdef CCMATH_HAS_SIMD + #ifdef CCMATH_HAS_SIMD_AVX2 +namespace ccm::intrin +{ + + CCM_ALWAYS_INLINE simd pow(simd const & a, simd const & b) + { + // NOLINTNEXTLINE(modernize-return-braced-init-list) + return simd(_mm256_pow_ps(a.get(), b.get())); + } + + CCM_ALWAYS_INLINE simd pow(simd const & a, simd const & b) + { + // NOLINTNEXTLINE(modernize-return-braced-init-list) + return simd(_mm256_pow_pd(a.get(), b.get())); + + } + +} // namespace ccm::intrin + + #endif // CCMATH_HAS_SIMD_AVX2 +#endif // CCMATH_HAS_SIMD diff --git a/include/ccmath/internal/math/runtime/simd/func/impl/avx512/pow.hpp b/include/ccmath/internal/math/runtime/simd/func/impl/avx512/pow.hpp new file mode 100644 index 0000000..922d10b --- /dev/null +++ b/include/ccmath/internal/math/runtime/simd/func/impl/avx512/pow.hpp @@ -0,0 +1,35 @@ +/* + * Copyright (c) Ian Pike + * Copyright (c) CCMath contributors + * + * CCMath is provided under the Apache-2.0 License WITH LLVM-exception. + * See LICENSE for more information. + * + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#pragma once + +#include "ccmath/internal/math/runtime/simd/simd.hpp" + +#ifdef CCMATH_HAS_SIMD + #ifdef CCMATH_HAS_SIMD_AVX512F +namespace ccm::intrin +{ + CCM_ALWAYS_INLINE simd pow(simd const & a, simd const & b) + { + // NOLINTNEXTLINE(modernize-return-braced-init-list) + return simd(_mm256_pow_ps(a.get(), b.get())); + } + + CCM_ALWAYS_INLINE simd pow(simd const & a, simd const & b) + { + // NOLINTNEXTLINE(modernize-return-braced-init-list) + return simd(_mm256_pow_pd(a.get(), b.get())); + + } + +} // namespace ccm::intrin + + #endif // CCMATH_HAS_SIMD_AVX512F +#endif // CCMATH_HAS_SIMD diff --git a/include/ccmath/internal/math/runtime/simd/func/impl/neon/pow.hpp b/include/ccmath/internal/math/runtime/simd/func/impl/neon/pow.hpp new file mode 100644 index 0000000..3cabc66 --- /dev/null +++ b/include/ccmath/internal/math/runtime/simd/func/impl/neon/pow.hpp @@ -0,0 +1,33 @@ +/* + * Copyright (c) Ian Pike + * Copyright (c) CCMath contributors + * + * CCMath is provided under the Apache-2.0 License WITH LLVM-exception. + * See LICENSE for more information. + * + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#pragma once + +#include "ccmath/internal/math/runtime/simd/simd.hpp" + +#ifdef CCMATH_HAS_SIMD + #ifdef CCMATH_HAS_SIMD_NEON +namespace ccm::intrin +{ + CCM_ALWAYS_INLINE simd sqrt(simd const & a) + { + // NOLINTNEXTLINE(modernize-return-braced-init-list) + return simd(vsqrtq_f32(a.get())); + } + + CCM_ALWAYS_INLINE simd sqrt(simd const & a) + { + // NOLINTNEXTLINE(modernize-return-braced-init-list) + return simd(vsqrtq_f64(a.get())); + } +} // namespace ccm::intrin + + #endif // CCMATH_HAS_SIMD_NEON +#endif // CCMATH_HAS_SIMD diff --git a/include/ccmath/internal/math/runtime/simd/func/impl/scalar/pow.hpp b/include/ccmath/internal/math/runtime/simd/func/impl/scalar/pow.hpp new file mode 100644 index 0000000..63bc9b4 --- /dev/null +++ b/include/ccmath/internal/math/runtime/simd/func/impl/scalar/pow.hpp @@ -0,0 +1,23 @@ +/* + * Copyright (c) Ian Pike + * Copyright (c) CCMath contributors + * + * CCMath is provided under the Apache-2.0 License WITH LLVM-exception. + * See LICENSE for more information. + * + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#pragma once + +#include "ccmath/internal/math/generic/func/power/sqrt_gen.hpp" +#include "ccmath/internal/math/runtime/simd/simd.hpp" + +namespace ccm::intrin +{ + template + CCM_ALWAYS_INLINE CCM_GPU_HOST_DEVICE simd sqrt(simd const& a) + { + return simd(ccm::gen::sqrt_gen(a.get())); + } +} // namespace ccm::intrin diff --git a/include/ccmath/internal/math/runtime/simd/func/impl/sse2/pow.hpp b/include/ccmath/internal/math/runtime/simd/func/impl/sse2/pow.hpp new file mode 100644 index 0000000..4478e56 --- /dev/null +++ b/include/ccmath/internal/math/runtime/simd/func/impl/sse2/pow.hpp @@ -0,0 +1,33 @@ +/* + * Copyright (c) Ian Pike + * Copyright (c) CCMath contributors + * + * CCMath is provided under the Apache-2.0 License WITH LLVM-exception. + * See LICENSE for more information. + * + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#pragma once + +#include "ccmath/internal/math/runtime/simd/simd.hpp" + +#ifdef CCMATH_HAS_SIMD + #ifdef CCMATH_HAS_SIMD_SSE2 +namespace ccm::intrin +{ + CCM_ALWAYS_INLINE simd sqrt(simd const & a) + { + // NOLINTNEXTLINE(modernize-return-braced-init-list) + return simd(_mm_sqrt_ps(a.get())); + } + + CCM_ALWAYS_INLINE simd sqrt(simd const & a) + { + // NOLINTNEXTLINE(modernize-return-braced-init-list) + return simd(_mm_sqrt_pd(a.get())); + } +} // namespace ccm::intrin + + #endif // CCMATH_HAS_SIMD_SSE2 +#endif // CCMATH_HAS_SIMD diff --git a/include/ccmath/internal/math/runtime/simd/func/impl/sse3/pow.hpp b/include/ccmath/internal/math/runtime/simd/func/impl/sse3/pow.hpp new file mode 100644 index 0000000..c9e5a03 --- /dev/null +++ b/include/ccmath/internal/math/runtime/simd/func/impl/sse3/pow.hpp @@ -0,0 +1,33 @@ +/* + * Copyright (c) Ian Pike + * Copyright (c) CCMath contributors + * + * CCMath is provided under the Apache-2.0 License WITH LLVM-exception. + * See LICENSE for more information. + * + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#pragma once + +#include "ccmath/internal/math/runtime/simd/simd.hpp" + +#ifdef CCMATH_HAS_SIMD + #ifdef CCMATH_HAS_SIMD_SSE3 +namespace ccm::intrin +{ + CCM_ALWAYS_INLINE simd sqrt(simd const & a) + { + // NOLINTNEXTLINE(modernize-return-braced-init-list) + return simd(_mm_sqrt_ps(a.get())); + } + + CCM_ALWAYS_INLINE simd sqrt(simd const & a) + { + // NOLINTNEXTLINE(modernize-return-braced-init-list) + return simd(_mm_sqrt_pd(a.get())); + } +} // namespace ccm::intrin + + #endif // CCMATH_HAS_SIMD_SSE3 +#endif // CCMATH_HAS_SIMD diff --git a/include/ccmath/internal/math/runtime/simd/func/impl/sse4/pow.hpp b/include/ccmath/internal/math/runtime/simd/func/impl/sse4/pow.hpp new file mode 100644 index 0000000..e2a782e --- /dev/null +++ b/include/ccmath/internal/math/runtime/simd/func/impl/sse4/pow.hpp @@ -0,0 +1,33 @@ +/* + * Copyright (c) Ian Pike + * Copyright (c) CCMath contributors + * + * CCMath is provided under the Apache-2.0 License WITH LLVM-exception. + * See LICENSE for more information. + * + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#pragma once + +#include "ccmath/internal/math/runtime/simd/simd.hpp" + +#ifdef CCMATH_HAS_SIMD + #ifdef CCMATH_HAS_SIMD_SSE4 +namespace ccm::intrin +{ + CCM_ALWAYS_INLINE simd sqrt(simd const & a) + { + // NOLINTNEXTLINE(modernize-return-braced-init-list) + return simd(_mm_sqrt_ps(a.get())); + } + + CCM_ALWAYS_INLINE simd sqrt(simd const & a) + { + // NOLINTNEXTLINE(modernize-return-braced-init-list) + return simd(_mm_sqrt_pd(a.get())); + } +} // namespace ccm::intrin + + #endif // CCMATH_HAS_SIMD_SSE4 +#endif // CCMATH_HAS_SIMD diff --git a/include/ccmath/internal/math/runtime/simd/func/impl/ssse3/pow.hpp b/include/ccmath/internal/math/runtime/simd/func/impl/ssse3/pow.hpp new file mode 100644 index 0000000..9be1907 --- /dev/null +++ b/include/ccmath/internal/math/runtime/simd/func/impl/ssse3/pow.hpp @@ -0,0 +1,33 @@ +/* + * Copyright (c) Ian Pike + * Copyright (c) CCMath contributors + * + * CCMath is provided under the Apache-2.0 License WITH LLVM-exception. + * See LICENSE for more information. + * + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#pragma once + +#include "ccmath/internal/math/runtime/simd/simd.hpp" + +#ifdef CCMATH_HAS_SIMD + #ifdef CCMATH_HAS_SIMD_SSSE3 +namespace ccm::intrin +{ + CCM_ALWAYS_INLINE simd sqrt(simd const & a) + { + // NOLINTNEXTLINE(modernize-return-braced-init-list) + return simd(_mm_sqrt_ps(a.get())); + } + + CCM_ALWAYS_INLINE simd sqrt(simd const & a) + { + // NOLINTNEXTLINE(modernize-return-braced-init-list) + return simd(_mm_sqrt_pd(a.get())); + } +} // namespace ccm::intrin + + #endif // CCMATH_HAS_SIMD_SSSE3 +#endif // CCMATH_HAS_SIMD diff --git a/include/ccmath/internal/math/runtime/simd/func/impl/vector_size/pow.hpp b/include/ccmath/internal/math/runtime/simd/func/impl/vector_size/pow.hpp new file mode 100644 index 0000000..81aecc7 --- /dev/null +++ b/include/ccmath/internal/math/runtime/simd/func/impl/vector_size/pow.hpp @@ -0,0 +1,38 @@ +/* + * Copyright (c) Ian Pike + * Copyright (c) CCMath contributors + * + * CCMath is provided under the Apache-2.0 License WITH LLVM-exception. + * See LICENSE for more information. + * + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#pragma once + +#include "ccmath/internal/math/runtime/simd/simd.hpp" + +#ifdef CCMATH_HAS_SIMD + #ifdef CCMATH_HAS_SIMD_ENABLE_VECTOR_SIZE + +namespace ccm::intrin +{ + + template + CCM_ALWAYS_INLINE CCM_GPU_HOST_DEVICE simd> sqrt(simd> const & a) + { + simd> result; + + // TODO: Implement a runtime vector_size sqrt that is optimized for runtime. + //CCM_SIMD_VECTORIZE for (int i = 0; i < a.size(); ++i) + //{ + // result.get()[i] = sqrt(a[i]); + //} + + return result; + } + +} // namespace ccm::intrin + + #endif // CCMATH_HAS_SIMD_ENABLE_VECTOR_SIZE +#endif // CCMATH_HAS_SIMD diff --git a/include/ccmath/internal/math/runtime/simd/func/pow.hpp b/include/ccmath/internal/math/runtime/simd/func/pow.hpp new file mode 100644 index 0000000..c760ade --- /dev/null +++ b/include/ccmath/internal/math/runtime/simd/func/pow.hpp @@ -0,0 +1,14 @@ +/* + * Copyright (c) Ian Pike + * Copyright (c) CCMath contributors + * + * CCMath is provided under the Apache-2.0 License WITH LLVM-exception. + * See LICENSE for more information. + * + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#pragma once + +#include "ccmath/internal/config/arch/check_simd_support.hpp" + diff --git a/include/ccmath/math/power/impl/pow_impl.hpp b/include/ccmath/math/power/impl/pow_impl.hpp deleted file mode 100644 index a7224d0..0000000 --- a/include/ccmath/math/power/impl/pow_impl.hpp +++ /dev/null @@ -1,294 +0,0 @@ -/* - * Copyright (c) Ian Pike - * Copyright (c) CCMath contributors - * - * CCMath is provided under the Apache-2.0 License WITH LLVM-exception. - * See LICENSE for more information. - * - * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - */ - -#pragma once - -// turn on fenv access -// #pragma STDC FENV_ACCESS ON - -#include "ccmath/internal/support/floating_point_traits.hpp" -#include "ccmath/internal/support/fp/bit_mask_traits.hpp" -#include "ccmath/internal/support/fp/directional_rounding_utils.hpp" -#include "ccmath/internal/support/fp/fp_bits.hpp" -#include "ccmath/internal/support/unreachable.hpp" -#include "ccmath/internal/types/big_int.hpp" -#include "ccmath/math/basic/abs.hpp" -#include "ccmath/math/compare/isnan.hpp" -#include "ccmath/math/power/sqrt.hpp" - -#include - -namespace ccm::internal::impl -{ - template - constexpr T pow_exp_helper(T base, T exp) noexcept - { - return 0; - } - - template - constexpr T pow_log_helper(T base, T exp) noexcept - { - return 0; - } - - template - constexpr T pow_round_even(T x) noexcept - { - return ccm::support::fp::directional_round(x, FE_TONEAREST); - } - - template , bool> = true> - constexpr auto convert_fp_to_uint(T x) noexcept - { - using FPbits_t = support::fp::FPBits; - using Storage_t = typename FPbits_t::storage_type; - FPbits_t x_bits(x); - Storage_t x_abs = x_bits.abs().uintval(); - return x_abs; - } - - template - constexpr bool pow_impl_is_integer(T x) noexcept - { - return ccm::support::fp::directional_round(x, FE_TONEAREST) == x; - } - - template , bool> = true> - constexpr bool is_odd_integer(T x) - { - using FPBits_t = typename support::fp::FPBits; - using Storage_t = typename FPBits_t::storage_type; - using SignedStorage_t = support::float_signed_bits_t; - auto x_u = support::bit_cast(x); - auto x_e = static_cast((x_u & FPBits_t::exponent_mask) >> FPBits_t::fraction_length); - auto lsb = support::countr_zero(x_u | FPBits_t::exponent_mask); - constexpr auto UNIT_EXPONENT = FPBits_t::exponent_bias + static_cast(FPBits_t::fraction_length); - return (x_e + lsb == UNIT_EXPONENT); - } - - template , bool> = true> - constexpr bool is_integer(T x) - { - using FPBits_t = typename support::fp::FPBits; - using Storage_t = typename FPBits_t::storage_type; - using SignedStorage_t = support::float_signed_bits_t; - Storage_t x_u = support::bit_cast(x); - auto x_e = static_cast((x_u & FPBits_t::exponent_mask) >> FPBits_t::fraction_length); - SignedStorage_t lsb = support::countr_zero(x_u | FPBits_t::exponent_mask); - constexpr SignedStorage_t UNIT_EXPONENT = FPBits_t::exponent_bias + static_cast(FPBits_t::fraction_length); - return (x_e + lsb >= UNIT_EXPONENT); - } - - template - // NOLINTNEXTLINE(readability-function-cognitive-complexity) - Has a naturally high complexity. To avoid fracturing, we allow this. - constexpr std::enable_if_t, T> pow_impl_handle_special_cases(support::fp::FPBits & x_bits, support::fp::FPBits & y_bits, - T & x, T & y) noexcept - { - if (x_bits.is_nan()) - { - // IEEE 754-2019: pow(x, ±0) = 1 if x is not a signaling NaN - if (y == 0.0 && !x_bits.is_signaling_nan()) { return 1.0; } - - // For GCC based compilers, they do not account for signaling nan and just return 1.0 - // For clang, it will return 1.0 if the optimization flag is set. - // AppleClang always returns 1 no matter the optimization level. -#if (defined(__GNUC__) && !defined(__clang__)) || (defined(__clang__) && defined(__OPTIMIZE__)) || (defined(__clang__) && defined(__APPLE__)) || \ - (defined(__clang__) && defined(CCM_CONFIG_AGGRESSIVELY_OPTIMIZE)) || defined(__INTEL_LLVM_COMPILER) - if (y == 0.0 && x_bits.is_signaling_nan()) { return 1.0; } -#endif - - return x + x; - } - - if (y_bits.is_nan()) - { - // IEEE 754-2019: pow(1,y) = 1 for any y (even a quiet NaN) - if (x == 1.0 && !y_bits.is_signaling_nan()) { return 1.0; } - - // For GCC based compilers, they do not account for signaling nan and just return 1.0 - // For clang, it will return 1.0 if the optimization flag is set. - // AppleClang always returns 1 no matter the optimization level. -#if (defined(__GNUC__) && !defined(__clang__)) || (defined(__clang__) && defined(__OPTIMIZE__)) || (defined(__clang__) && defined(__APPLE__)) || \ - (defined(__clang__) && defined(CCM_CONFIG_AGGRESSIVELY_OPTIMIZE)) || defined(__INTEL_LLVM_COMPILER) - if (x == 1.0 && y_bits.is_signaling_nan()) { return 1.0; } -#endif - - return y + y; - } - - // Handle the special case where x is a positive infinity and y is not negative - // x = +inf - if (x_bits.is_inf() && !x_bits.is_neg()) - { - if (y == 0.0) { return 1.0; } - - if (y < 0.0) { return 0.0; } - - if (y > 0.0) { return std::numeric_limits::infinity(); } - } - - // Handle the special case where x is a negative infinity - // x = -inf - if (x_bits.is_inf() && x_bits.is_neg()) - { - // If y is an odd integer - if (pow_impl_is_integer(y) && !pow_impl_is_integer(y * std::numeric_limits::round_error())) - { - // y is a negative odd integer - if (y < 0.0) { return -0.0; } - - // y is a positive odd integer - return -std::numeric_limits::infinity(); - } - - // y is a negative even integer or a negative non-integer - if (y < 0.0) { return 0.0; } - - // y is a positive even integer or a positive non-integer - if (y > 0.0) { return std::numeric_limits::infinity(); } - } - - // y = +inf - if (y_bits.is_inf() && !y_bits.is_neg()) - { - if (x == 0.0) { return 0.0; } - - if (x == -1.0 || x == 1.0) { return 1.0; } - - if (-1.0 < x && x < 1.0) { return 0.0; } - - if (x < -1.0 || 1.0 < x) { return std::numeric_limits::infinity(); } - } - - // y = -inf - if (y_bits.is_inf() && y_bits.is_neg()) - { - if (x == 0.0) { return std::numeric_limits::infinity(); } - - if (x == -1.0 || x == 1.0) { return 1.0; } - - if (-1.0 < x && x < 1.0) { return std::numeric_limits::infinity(); } - - if (x < -1.0 || 1.0 < x) { return 0.0; } - } - - support::unreachable(); // Something went horribly wrong if we reach this point. - return 0.0; // This should never be reached. - } - - template - constexpr std::enable_if_t, T> pow_impl_handle_zero_or_less(support::fp::FPBits & x_bits, T & x, T & y, - T & current_sign_of_result) noexcept - { - const bool is_x_zero = x_bits.is_zero(); - const bool is_y_an_integer = pow_impl_is_integer(y); - // x = +0.0 - if (is_x_zero && !x_bits.is_neg()) - { - // y is an odd integer - if (is_y_an_integer && !pow_impl_is_integer(y * std::numeric_limits::round_error())) - { - // y is a negative odd integer - if (y < 0.0) - { - ccm::support::fenv::raise_except_if_required(FE_DIVBYZERO); - return std::numeric_limits::infinity(); - } - - // y is a positive odd integer - return 0.0; - } - - // y is positive even integer or a positive non-integer - if (y > 0.0) { return 0.0; } - - // y is a negative, even, and finite integer or non-integer - ccm::support::fenv::raise_except_if_required(FE_DIVBYZERO); - return std::numeric_limits::infinity(); - } - - // x = -0.0 - if (is_x_zero) - { - // y is an odd integer - if (is_y_an_integer && !pow_impl_is_integer(y * std::numeric_limits::round_error())) - { - // y is a negative odd integer - if (y < 0.0) - { - ccm::support::fenv::raise_except_if_required(FE_DIVBYZERO); - return -std::numeric_limits::infinity(); - } - - // y is a positive odd integer - return -0.0; - } - - // y is a positive even integer or a positive non-integer - if (y > 0.0) { return 0.0; } - - // y is a negative, even, and finite integer or non-integer - ccm::support::fenv::raise_except_if_required(FE_DIVBYZERO); - return -std::numeric_limits::infinity(); - } - - if (!is_y_an_integer) - { - ccm::support::fenv::raise_except_if_required(FE_INVALID); - return std::numeric_limits::quiet_NaN(); - } - - std::array copy_sign = {1.0, -1.0}; - - // set sign to 1 for even y and -1 for odd y - int y_parity = ccm::abs(y) >= support::floating_point_traits::max_safe_integer ? 0 : static_cast>(y) & 0x1; - current_sign_of_result = copy_sign.at(static_cast(y_parity)); - - // Set x to the absolute value of x for the remainder of the function - x = -x; - - // Indicate that we did not get a case that could've been handled, so we just set x above - // then signal this by returning a max value of our type which this function would never return. - // We have to do this as we are modifying x at this point but don't yet intend to return the full function. - return std::numeric_limits::min(); - } - - // make sure TStorage is of the type support::fp::FPBits::storage_type - template ::storage_type>, bool> = true> - constexpr std::enable_if_t, T> pow_check_over_under_flow(support::fp::FPBits & x_bits, support::fp::FPBits & y_bits, - TStorage & x_abs, TStorage & y_abs) noexcept - { - - return 0; - } - - template - constexpr std::enable_if_t, T> pow_impl(T x, T y) noexcept - { - support::fp::FPBits x_bits(x); - support::fp::FPBits y_bits(y); - double sign_of_result = 1.0; - - // Handle edge cases when x or y is a non-finite value - if (CCM_UNLIKELY(!x_bits.is_finite() || !y_bits.is_finite())) { return pow_impl_handle_special_cases(x_bits, y_bits, x, y); } - - // Handle edge cases when x is zero or lees than zero - if (x <= 0.0) - { - const auto handling_zero_or_less_result = pow_impl_handle_zero_or_less(x_bits, x, y, sign_of_result); - if (handling_zero_or_less_result != std::numeric_limits::min()) { return handling_zero_or_less_result; } - } - // Begin the actual calculation - - return 0; - } - -} // namespace ccm::internal::impl diff --git a/include/ccmath/math/power/pow.hpp b/include/ccmath/math/power/pow.hpp index d4fed71..6aeb429 100644 --- a/include/ccmath/math/power/pow.hpp +++ b/include/ccmath/math/power/pow.hpp @@ -10,60 +10,25 @@ #pragma once -#include - -#include "ccmath/math/exponential/exp2.hpp" -#include "ccmath/math/exponential/log2.hpp" - -#include "ccmath/math/power/impl/pow_impl.hpp" +#include "ccmath/internal/math/generic/func/power/pow_gen.hpp" +#include "ccmath/internal/support/is_constant_evaluated.hpp" +#include namespace ccm { - // TODO: Much of this is going to be removed. New implementation is being worked on elsewhere. - namespace internal::impl - { - template && std::is_unsigned_v, bool> = true> - constexpr T pow_expo_by_sqr(T base, T exp) noexcept - { - // Handle common cases - if (exp == 0) { return 1; } // Anything to the power of 0 is 1 - if (exp == 1) { return base; } // Anything to the power of 1 is itself - if (exp == 2) { return base * base; } // Anything to the power of 2 is itself squared - if (base == 0) { return 0; } // 0 to any power is 0 - if (base == 1) { return 1; } // 1 to any power is 1 - - // If the base is 2, we can use the bit shift operator to calculate the power. - if (base == 2) { return 1 << exp; } - - // This is pretty fast with smaller numbers, but is slower than the standard when dealing with large numbers. - // TODO: Find a way to optimize this for larger numbers. - T result = 1; - for (;;) - { - if (exp & 1) { result *= base; } - exp >>= 1; - if (!exp) { break; } - base *= base; - } - return result; - } + template + constexpr T pow(T base, T exp) noexcept + { + // TODO: Add in usage of builtins that meet ccmath standards. - template , bool> = true> - constexpr T pow_generic(T base, T exp) noexcept + if (support::is_constant_evaluated()) { - // This should work on all x86 platforms but may not work with other architectures. - // For now this is more of a hold over till I have time to implement a better generic version. - return ccm::exp2(exp * ccm::log2(base)); + return gen::pow_gen(base, exp); } - } // namespace internal::impl - template - constexpr T pow(T base, T exp) noexcept - { - if constexpr (std::is_integral_v && std::is_unsigned_v) { return internal::impl::pow_expo_by_sqr(base, exp); } - return internal::impl::pow_generic(base, exp); + return gen::pow_gen(base, exp); // TODO: Replace once runtime implementation is hooked in. } } // namespace ccm