Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 22 additions & 12 deletions include/bitcoin/system/impl/math/power.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -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 <typename Value, typename Base, typename Exponent,
if_integer<Value> = true,
if_integer<Base> = true,
Expand All @@ -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;
Value product{ 1 };
while (exponent-- > 0u)
product *= possible_narrow_and_sign_cast<Value>(base);

auto value = possible_narrow_and_sign_cast<Value>(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()

return value;
return product;
}

// published
Expand Down Expand Up @@ -112,6 +105,23 @@ constexpr Value power2(Exponent exponent) NOEXCEPT
possible_narrow_and_sign_cast<unsigned>(exponent));
}

template <typename Float, typename Exponent,
if_floating_point<Float>,
if_unsigned_integer<Exponent>>
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

Expand Down
6 changes: 6 additions & 0 deletions include/bitcoin/system/math/power.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,12 @@ template <typename Value = size_t, typename Exponent,
if_unsigned_integer<Exponent> = true>
constexpr Value power2(Exponent exponent) NOEXCEPT;

/// Floating point constexpr optimization for integer exponent.
template <typename Float, typename Exponent,
if_floating_point<Float> = true,
if_unsigned_integer<Exponent> = true>
constexpr Float power(Float base, Exponent exponent) NOEXCEPT;

} // namespace system
} // namespace libbitcoin

Expand Down
21 changes: 17 additions & 4 deletions test/math/power.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,23 +37,21 @@ 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<uint16_t>(3, 11u) == 0xb3fb_u16);

static_assert(power(-1, 0u) == 1u);
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<uint16_t>(-3, 11u) == 0x4c05_u16);

// power2
static_assert(power2(0u) == 1u);
static_assert(power2(0u) == 1u);
static_assert(power2(1u) == 2u);
static_assert(power2(1u) == 2u);
static_assert(power2<uint16_t>(15u) == 0b1000'0000'0000'0000_u16);
static_assert(power2<uint16_t>(16u) == 0_u16);
static_assert(power2<uint16_t>(16u) == 0_u16); // overflow

// power<>
static_assert(power<0>(16u) == power(0u, 16u));
Expand All @@ -66,10 +64,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<decltype(power(0.0f, 0u)), float>);
static_assert(is_same_type<decltype(power(0.0, 0u)), double>);

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);
Expand Down
Loading