Skip to content

Commit 3ebfb24

Browse files
authored
Merge pull request #560 from cppalliance/fix_basic
Improve some basic 128-bit operations
2 parents b996363 + 576011b commit 3ebfb24

File tree

3 files changed

+97
-13
lines changed

3 files changed

+97
-13
lines changed

include/boost/decimal/decimal128.hpp

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1439,7 +1439,7 @@ constexpr auto d128_add_impl(T1 lhs_sig, std::int32_t lhs_exp, bool lhs_sign,
14391439

14401440
BOOST_DECIMAL_IF_CONSTEXPR (std::numeric_limits<T2>::digits10 > std::numeric_limits<std::uint64_t>::digits10)
14411441
{
1442-
if (rhs_sig >= detail::uint128 {500'000'000'000'000, 0})
1442+
if (rhs_sig >= detail::uint128 {UINT64_C(0xF684DF56C3E0), UINT64_C(0x1BC6C73200000000)})
14431443
{
14441444
++lhs_sig;
14451445
}
@@ -1459,12 +1459,9 @@ constexpr auto d128_add_impl(T1 lhs_sig, std::int32_t lhs_exp, bool lhs_sign,
14591459

14601460
if (delta_exp <= 3)
14611461
{
1462-
while (delta_exp > 0)
1463-
{
1464-
lhs_sig *= 10;
1465-
--delta_exp;
1466-
--lhs_exp;
1467-
}
1462+
lhs_sig *= detail::pow10(static_cast<detail::uint128>(delta_exp));
1463+
lhs_exp -= delta_exp;
1464+
delta_exp = 0;
14681465
}
14691466
else
14701467
{
@@ -1475,8 +1472,8 @@ constexpr auto d128_add_impl(T1 lhs_sig, std::int32_t lhs_exp, bool lhs_sign,
14751472

14761473
while (delta_exp > 1)
14771474
{
1478-
rhs_sig /= 10;
1479-
--delta_exp;
1475+
rhs_sig /= detail::pow10(static_cast<detail::uint128>(delta_exp - 1));
1476+
delta_exp = 1;
14801477
}
14811478

14821479
if (delta_exp == 1)
@@ -1539,8 +1536,8 @@ constexpr auto d128_sub_impl(T1 lhs_sig, std::int32_t lhs_exp, bool lhs_sign,
15391536

15401537
while (delta_exp > 1)
15411538
{
1542-
sig_smaller /= 10;
1543-
--delta_exp;
1539+
sig_smaller /= detail::pow10(static_cast<detail::uint128>(delta_exp - 1));
1540+
delta_exp = 1;
15441541
}
15451542

15461543
if (delta_exp == 1)

include/boost/decimal/detail/integer_search_trees.hpp

Lines changed: 87 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,53 @@ constexpr auto num_digits(std::uint64_t x) noexcept -> int
166166
# pragma warning(disable: 4307) // MSVC 14.1 warns of intergral constant overflow
167167
#endif
168168

169+
#if defined(__cpp_lib_array_constexpr) && __cpp_lib_array_constexpr >= 201603L
170+
171+
template <typename T, std::size_t N>
172+
constexpr auto generate_array() noexcept -> std::array<T, N>
173+
{
174+
std::array<T, N> values {};
175+
176+
values[0] = 1;
177+
for (std::size_t i {1}; i < N; ++i)
178+
{
179+
values[i] = values[i - 1] * 10;
180+
}
181+
182+
return values;
183+
}
184+
185+
constexpr int num_digits(uint128 x) noexcept
186+
{
187+
constexpr auto big_powers_of_10 = generate_array<boost::decimal::detail::uint128, 39>();
188+
189+
if (x == 0)
190+
{
191+
return 1;
192+
}
193+
194+
std::uint32_t left = 0U;
195+
std::uint32_t right = 38U;
196+
197+
while (left < right)
198+
{
199+
std::uint32_t mid = (left + right + 1U) / 2U;
200+
201+
if (x >= big_powers_of_10[mid])
202+
{
203+
left = mid;
204+
}
205+
else
206+
{
207+
right = mid - 1;
208+
}
209+
}
210+
211+
return static_cast<int>(left + 1);
212+
}
213+
214+
#else
215+
169216
constexpr int num_digits(uint128 x) noexcept
170217
{
171218
if (x.high == 0)
@@ -190,6 +237,8 @@ constexpr int num_digits(uint128 x) noexcept
190237
return 1;
191238
}
192239

240+
#endif // Constexpr array
241+
193242
constexpr int num_digits(const uint256_t& x) noexcept
194243
{
195244
if (x.high == 0)
@@ -222,6 +271,40 @@ constexpr int num_digits(const uint256_t& x) noexcept
222271
#endif
223272

224273
#ifdef BOOST_DECIMAL_HAS_INT128
274+
275+
#if defined(__cpp_lib_array_constexpr) && __cpp_lib_array_constexpr >= 201603L
276+
277+
constexpr auto num_digits(boost::decimal::detail::uint128_t x) noexcept -> int
278+
{
279+
constexpr auto big_powers_of_10 = generate_array<boost::decimal::detail::uint128_t, 39>();
280+
281+
if (x == 0)
282+
{
283+
return 1;
284+
}
285+
286+
std::uint32_t left = 0U;
287+
std::uint32_t right = 38U;
288+
289+
while (left < right)
290+
{
291+
std::uint32_t mid = (left + right + 1U) / 2U;
292+
293+
if (x >= big_powers_of_10[mid])
294+
{
295+
left = mid;
296+
}
297+
else
298+
{
299+
right = mid - 1;
300+
}
301+
}
302+
303+
return static_cast<int>(left + 1);
304+
}
305+
306+
#else
307+
225308
// Assume that if someone is using 128 bit ints they are favoring the top end of the range
226309
// Max value is 340,282,366,920,938,463,463,374,607,431,768,211,455 (39 digits)
227310
constexpr auto num_digits(boost::decimal::detail::uint128_t x) noexcept -> int
@@ -290,7 +373,10 @@ constexpr auto num_digits(boost::decimal::detail::uint128_t x) noexcept -> int
290373
(x >= powers_of_10[1]) ? 2 :
291374
(x >= powers_of_10[0]) ? 1 : 0;
292375
}
293-
#endif
376+
377+
#endif // constexpr arrays
378+
379+
#endif // Has int128
294380

295381
} // namespace detail
296382
} // namespace decimal

test/test_to_chars.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ static constexpr auto N = static_cast<std::size_t>(1024U); // Number of trials
1919
static constexpr auto N = static_cast<std::size_t>(1024U >> 4U); // Number of trials
2020
#endif
2121

22-
#if !defined(BOOST_DECIMAL_DISABLE_CLIB)
22+
// stringop overflow errors from gcc-13 and on with x86
23+
#if !defined(BOOST_DECIMAL_DISABLE_CLIB) && !(defined(__GNUC__) && __GNUC__ >= 13 && !defined(__aarch64__))
2324

2425
template <typename T>
2526
void test_value(T val, const char* result, chars_format fmt = boost::decimal::chars_format::general, int precision = -1)

0 commit comments

Comments
 (0)