Skip to content

Commit 44622f7

Browse files
authored
Merge pull request #1784 from evoskuil/master
Add constexpr Float power(Float base, Exponent exponent), style.
2 parents a78f904 + 110c89d commit 44622f7

3 files changed

Lines changed: 45 additions & 16 deletions

File tree

include/bitcoin/system/impl/math/power.ipp

Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ namespace system {
3333

3434
// Called by bc::base85 (for number coding).
3535
// Called by wallet::electrum_v1 (for number coding).
36+
// Overflow is allowed behavior as this models a mathematical operator.
3637
template <typename Value, typename Base, typename Exponent,
3738
if_integer<Value> = true,
3839
if_integer<Base> = true,
@@ -42,19 +43,11 @@ constexpr Value power_(Base base, Exponent exponent) NOEXCEPT
4243
if (is_power_overflow(base, exponent))
4344
return 0;
4445

45-
if (is_zero(exponent))
46-
return 1;
46+
Value product{ 1 };
47+
while (exponent-- > 0u)
48+
product *= possible_narrow_and_sign_cast<Value>(base);
4749

48-
auto value = possible_narrow_and_sign_cast<Value>(base);
49-
50-
// Overflow is allowed behavior as this models a mathematical operator.
51-
BC_PUSH_WARNING(NARROWING_CONVERSION)
52-
BC_PUSH_WARNING(SIZE_NARROWING_CONVERSION)
53-
while (--exponent > 0u) { value *= base; }
54-
BC_POP_WARNING()
55-
BC_POP_WARNING()
56-
57-
return value;
50+
return product;
5851
}
5952

6053
// published
@@ -112,6 +105,23 @@ constexpr Value power2(Exponent exponent) NOEXCEPT
112105
possible_narrow_and_sign_cast<unsigned>(exponent));
113106
}
114107

108+
template <typename Float, typename Exponent,
109+
if_floating_point<Float>,
110+
if_unsigned_integer<Exponent>>
111+
constexpr Float power(Float base, Exponent exponent) NOEXCEPT
112+
{
113+
// 0^0 is undefined, return 0.
114+
if ((base == 0.0) && is_zero(exponent))
115+
return 0.0;
116+
117+
Float product{ 1.0 };
118+
while (exponent-- > 0u)
119+
if ((product *= base) == 0.0)
120+
break;
121+
122+
return product;
123+
}
124+
115125
} // namespace system
116126
} // namespace libbitcoin
117127

include/bitcoin/system/math/power.hpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,12 @@ template <typename Value = size_t, typename Exponent,
5454
if_unsigned_integer<Exponent> = true>
5555
constexpr Value power2(Exponent exponent) NOEXCEPT;
5656

57+
/// Floating point constexpr optimization for integer exponent.
58+
template <typename Float, typename Exponent,
59+
if_floating_point<Float> = true,
60+
if_unsigned_integer<Exponent> = true>
61+
constexpr Float power(Float base, Exponent exponent) NOEXCEPT;
62+
5763
} // namespace system
5864
} // namespace libbitcoin
5965

test/math/power.cpp

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,23 +37,21 @@ static_assert(power(3, 0u) == 1u);
3737
static_assert(power(3u, 0u) == 1u);
3838
static_assert(power(3, 10u) == 0xe6a9_size);
3939
static_assert(power(3u, 10u) == 0xe6a9_size);
40-
static_assert(power<uint16_t>(3, 11u) == 0xb3fb_u16);
4140

4241
static_assert(power(-1, 0u) == 1u);
4342
static_assert(power(-1, 1u) == 1_nsize);
4443

4544
static_assert(power(-3, 0u) == 1u);
4645
static_assert(power(-3, 1u) == 3_nsize);
4746
static_assert(power(-3, 10u) == 0xe6a9_size);
48-
static_assert(power<uint16_t>(-3, 11u) == 0x4c05_u16);
4947

5048
// power2
5149
static_assert(power2(0u) == 1u);
5250
static_assert(power2(0u) == 1u);
5351
static_assert(power2(1u) == 2u);
5452
static_assert(power2(1u) == 2u);
5553
static_assert(power2<uint16_t>(15u) == 0b1000'0000'0000'0000_u16);
56-
static_assert(power2<uint16_t>(16u) == 0_u16);
54+
static_assert(power2<uint16_t>(16u) == 0_u16); // overflow
5755

5856
// power<>
5957
static_assert(power<0>(16u) == power(0u, 16u));
@@ -66,10 +64,25 @@ static_assert(power<3, size_t>(0u) == 1u);
6664
// uint256_t
6765
static_assert(power<2u, uint256_t>(10u) == 1024u);
6866

69-
// uintx is not constexpr.
67+
68+
// floating point
69+
static_assert(is_same_type<decltype(power(0.0f, 0u)), float>);
70+
static_assert(is_same_type<decltype(power(0.0, 0u)), double>);
71+
72+
static_assert(power(0.0f, 0u) == 0.0f);
73+
static_assert(power(0.0, 0u) == 0.0);
74+
static_assert(power(1.0, 0u) == 1.0);
75+
static_assert(power(1.0, 1u) == 1.0);
76+
static_assert(power(2.0, 1u) == 2.0);
77+
static_assert(power(2.0, 2u) == 4.0);
78+
static_assert(power(3.0, 3u) == 27.0);
79+
80+
// Actually 311.1696 but this is the floating point representation.
81+
static_assert(power(4.2, 4u) == 311.16960000000006);
7082

7183
BOOST_AUTO_TEST_SUITE(power_tests)
7284

85+
// uintx is not constexpr.
7386
BOOST_AUTO_TEST_CASE(power_uintx_tests)
7487
{
7588
BOOST_REQUIRE(true);

0 commit comments

Comments
 (0)