From 41bbd829d1cdb649f19ab493bde39ce031cc3fb1 Mon Sep 17 00:00:00 2001 From: evoskuil Date: Fri, 20 Feb 2026 15:31:21 -0500 Subject: [PATCH 1/2] Add constexpr Float power(Float base, Exponent exponent). --- include/bitcoin/system/impl/math/power.ipp | 17 +++++++++++++++++ include/bitcoin/system/math/power.hpp | 6 ++++++ test/math/power.cpp | 17 ++++++++++++++++- 3 files changed, 39 insertions(+), 1 deletion(-) diff --git a/include/bitcoin/system/impl/math/power.ipp b/include/bitcoin/system/impl/math/power.ipp index 967c03f6fc..4245486bde 100644 --- a/include/bitcoin/system/impl/math/power.ipp +++ b/include/bitcoin/system/impl/math/power.ipp @@ -112,6 +112,23 @@ constexpr Value power2(Exponent exponent) NOEXCEPT possible_narrow_and_sign_cast(exponent)); } +template , + if_unsigned_integer> +constexpr Float power(Float base, Exponent exponent) NOEXCEPT +{ + // 0^0 is undefined, return 0. + if ((base == 0.0) && is_zero(exponent)) + return 0.0; + + Float product{ 1.0 }; + while (exponent-- > 0u) + if ((product *= base) == 0.0) + break; + + return product; +} + } // namespace system } // namespace libbitcoin diff --git a/include/bitcoin/system/math/power.hpp b/include/bitcoin/system/math/power.hpp index 59652aa2a5..52eed75ab6 100644 --- a/include/bitcoin/system/math/power.hpp +++ b/include/bitcoin/system/math/power.hpp @@ -54,6 +54,12 @@ template = true> constexpr Value power2(Exponent exponent) NOEXCEPT; +/// Floating point constexpr optimization for integer exponent. +template = true, + if_unsigned_integer = true> +constexpr Float power(Float base, Exponent exponent) NOEXCEPT; + } // namespace system } // namespace libbitcoin diff --git a/test/math/power.cpp b/test/math/power.cpp index af595a308e..bf7c7ebb08 100644 --- a/test/math/power.cpp +++ b/test/math/power.cpp @@ -66,10 +66,25 @@ static_assert(power<3, size_t>(0u) == 1u); // uint256_t static_assert(power<2u, uint256_t>(10u) == 1024u); -// uintx is not constexpr. + +// floating point +static_assert(is_same_type); +static_assert(is_same_type); + +static_assert(power(0.0f, 0u) == 0.0f); +static_assert(power(0.0, 0u) == 0.0); +static_assert(power(1.0, 0u) == 1.0); +static_assert(power(1.0, 1u) == 1.0); +static_assert(power(2.0, 1u) == 2.0); +static_assert(power(2.0, 2u) == 4.0); +static_assert(power(3.0, 3u) == 27.0); + +// Actually 311.1696 but this is the floating point representation. +static_assert(power(4.2, 4u) == 311.16960000000006); BOOST_AUTO_TEST_SUITE(power_tests) +// uintx is not constexpr. BOOST_AUTO_TEST_CASE(power_uintx_tests) { BOOST_REQUIRE(true); From 110c89dd9e160a7332ec45c07a5e2a7791270766 Mon Sep 17 00:00:00 2001 From: evoskuil Date: Fri, 20 Feb 2026 16:11:25 -0500 Subject: [PATCH 2/2] Style (normalize power implementations). --- include/bitcoin/system/impl/math/power.ipp | 17 +++++------------ test/math/power.cpp | 4 +--- 2 files changed, 6 insertions(+), 15 deletions(-) diff --git a/include/bitcoin/system/impl/math/power.ipp b/include/bitcoin/system/impl/math/power.ipp index 4245486bde..cf3f36f79e 100644 --- a/include/bitcoin/system/impl/math/power.ipp +++ b/include/bitcoin/system/impl/math/power.ipp @@ -33,6 +33,7 @@ namespace system { // Called by bc::base85 (for number coding). // Called by wallet::electrum_v1 (for number coding). +// Overflow is allowed behavior as this models a mathematical operator. template = true, if_integer = true, @@ -42,19 +43,11 @@ constexpr Value power_(Base base, Exponent exponent) NOEXCEPT if (is_power_overflow(base, exponent)) return 0; - if (is_zero(exponent)) - return 1; - - auto value = possible_narrow_and_sign_cast(base); - - // Overflow is allowed behavior as this models a mathematical operator. - BC_PUSH_WARNING(NARROWING_CONVERSION) - BC_PUSH_WARNING(SIZE_NARROWING_CONVERSION) - while (--exponent > 0u) { value *= base; } - BC_POP_WARNING() - BC_POP_WARNING() + Value product{ 1 }; + while (exponent-- > 0u) + product *= possible_narrow_and_sign_cast(base); - return value; + return product; } // published diff --git a/test/math/power.cpp b/test/math/power.cpp index bf7c7ebb08..8b74018e6f 100644 --- a/test/math/power.cpp +++ b/test/math/power.cpp @@ -37,7 +37,6 @@ static_assert(power(3, 0u) == 1u); static_assert(power(3u, 0u) == 1u); static_assert(power(3, 10u) == 0xe6a9_size); static_assert(power(3u, 10u) == 0xe6a9_size); -static_assert(power(3, 11u) == 0xb3fb_u16); static_assert(power(-1, 0u) == 1u); static_assert(power(-1, 1u) == 1_nsize); @@ -45,7 +44,6 @@ static_assert(power(-1, 1u) == 1_nsize); static_assert(power(-3, 0u) == 1u); static_assert(power(-3, 1u) == 3_nsize); static_assert(power(-3, 10u) == 0xe6a9_size); -static_assert(power(-3, 11u) == 0x4c05_u16); // power2 static_assert(power2(0u) == 1u); @@ -53,7 +51,7 @@ static_assert(power2(0u) == 1u); static_assert(power2(1u) == 2u); static_assert(power2(1u) == 2u); static_assert(power2(15u) == 0b1000'0000'0000'0000_u16); -static_assert(power2(16u) == 0_u16); +static_assert(power2(16u) == 0_u16); // overflow // power<> static_assert(power<0>(16u) == power(0u, 16u));