Skip to content

Commit 80060d2

Browse files
authored
Merge pull request #660 from cppalliance/256_search
Improve `num_digits()` for `uint256_t`
2 parents 556a5d2 + 0424598 commit 80060d2

File tree

2 files changed

+20
-96
lines changed

2 files changed

+20
-96
lines changed

include/boost/decimal/detail/integer_search_trees.hpp

Lines changed: 2 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -168,24 +168,6 @@ constexpr auto num_digits(std::uint64_t x) noexcept -> int
168168
# pragma warning(disable: 4307) // MSVC 14.1 warns of intergral constant overflow
169169
#endif
170170

171-
#if defined(__cpp_lib_array_constexpr) && __cpp_lib_array_constexpr >= 201603L
172-
173-
template <typename T, std::size_t N>
174-
constexpr auto generate_array() noexcept -> std::array<T, N>
175-
{
176-
std::array<T, N> values {};
177-
178-
values[0] = T{1};
179-
for (std::size_t i {1}; i < N; ++i)
180-
{
181-
values[i] = values[i - 1] * UINT64_C(10);
182-
}
183-
184-
return values;
185-
}
186-
187-
#else
188-
189171
constexpr int num_digits(const uint128& x) noexcept
190172
{
191173
if (x.high == UINT64_C(0))
@@ -214,54 +196,15 @@ constexpr int num_digits(const uint128& x) noexcept
214196
return static_cast<int>(left + 1);
215197
}
216198

217-
#endif // Constexpr array
218-
219-
#if defined(__cpp_lib_array_constexpr) && __cpp_lib_array_constexpr >= 201603L
220-
221-
constexpr int num_digits(const uint256_t& x) noexcept
222-
{
223-
constexpr auto big_powers_of_10 = generate_array<boost::decimal::detail::uint256_t, 79>();
224-
225-
if (x.high == UINT64_C(0) && x.low == UINT64_C(0))
226-
{
227-
return 1;
228-
}
229-
230-
std::uint32_t left = 0U;
231-
std::uint32_t right = 78U;
232-
233-
while (left < right)
234-
{
235-
std::uint32_t mid = (left + right + 1U) / 2U;
236-
237-
if (x >= big_powers_of_10[mid])
238-
{
239-
left = mid;
240-
}
241-
else
242-
{
243-
right = mid - 1;
244-
}
245-
}
246-
247-
return static_cast<int>(left + 1);
248-
}
249-
250-
#else
251-
252199
constexpr int num_digits(const uint256_t& x) noexcept
253200
{
254201
if (x.high == 0)
255202
{
256203
return num_digits(x.low);
257204
}
258205

259-
constexpr uint256_t max_digits = umul256({static_cast<uint128>(UINT64_C(10000000000000000000)) *
260-
static_cast<uint128>(UINT64_C(10000000000000000000))},
261-
{static_cast<uint128>(UINT64_C(10000000000000000000)) *
262-
static_cast<uint128>(UINT64_C(10000000000000000000))});
263-
264-
uint256_t current_power_of_10 = max_digits;
206+
// 10^77
207+
auto current_power_of_10 {uint256_t{uint128{UINT64_C(15930919111324522770), UINT64_C(5327493063679123134)}, uint128{UINT64_C(12292710897160462336), UINT64_C(0)}}};
265208

266209
for (int i = 78; i > 0; --i)
267210
{
@@ -276,47 +219,12 @@ constexpr int num_digits(const uint256_t& x) noexcept
276219
return 1;
277220
}
278221

279-
#endif // Constexpr arrays
280-
281222
#ifdef _MSC_VER
282223
# pragma warning(pop)
283224
#endif
284225

285226
#ifdef BOOST_DECIMAL_HAS_INT128
286227

287-
#if defined(__cpp_lib_array_constexpr) && __cpp_lib_array_constexpr >= 201603L
288-
289-
constexpr auto num_digits(boost::decimal::detail::uint128_t x) noexcept -> int
290-
{
291-
constexpr auto big_powers_of_10 = generate_array<boost::decimal::detail::uint128_t, 39>();
292-
293-
if (x == 0)
294-
{
295-
return 1;
296-
}
297-
298-
std::uint32_t left = 0U;
299-
std::uint32_t right = 38U;
300-
301-
while (left < right)
302-
{
303-
std::uint32_t mid = (left + right + 1U) / 2U;
304-
305-
if (x >= big_powers_of_10[mid])
306-
{
307-
left = mid;
308-
}
309-
else
310-
{
311-
right = mid - 1;
312-
}
313-
}
314-
315-
return static_cast<int>(left + 1);
316-
}
317-
318-
#else
319-
320228
constexpr auto num_digits(const uint128_t& x) noexcept -> int
321229
{
322230
if (static_cast<std::uint64_t>(x >> 64) == UINT64_C(0))
@@ -345,8 +253,6 @@ constexpr auto num_digits(const uint128_t& x) noexcept -> int
345253
return static_cast<int>(left + 1);
346254
}
347255

348-
#endif // constexpr arrays
349-
350256
#endif // Has int128
351257

352258
} // namespace detail

test/test_big_uints.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -458,6 +458,21 @@ auto test_big_uints_shl() -> void
458458
}
459459
}
460460

461+
template <typename T>
462+
void test_digit_counting()
463+
{
464+
constexpr auto max_power {std::is_same<T, boost::decimal::detail::uint256_t>::value ? 77 : 38 };
465+
466+
T current_power {1};
467+
int current_digits {1};
468+
for (int i {}; i <= max_power; ++i)
469+
{
470+
BOOST_TEST_EQ(num_digits(current_power), current_digits);
471+
current_power = current_power * UINT64_C(10);
472+
++current_digits;
473+
}
474+
}
475+
461476
int main()
462477
{
463478
test_big_uints_mul<boost::multiprecision::uint128_t, boost::decimal::detail::uint128 >();
@@ -475,6 +490,9 @@ int main()
475490
test_big_uints_shl<boost::multiprecision::uint128_t, boost::decimal::detail::uint128 >();
476491
test_big_uints_shl<boost::multiprecision::uint256_t, boost::decimal::detail::uint256_t>();
477492

493+
test_digit_counting<boost::decimal::detail::uint128>();
494+
test_digit_counting<boost::decimal::detail::uint256_t>();
495+
478496
return boost::report_errors();
479497
}
480498

0 commit comments

Comments
 (0)