Skip to content

Commit d7cc1d3

Browse files
authored
Merge pull request #658 from cppalliance/faster_dec128_fast
2 parents c7aed9d + 3c87b81 commit d7cc1d3

File tree

3 files changed

+59
-107
lines changed

3 files changed

+59
-107
lines changed

doc/decimal/benchmarks.adoc

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,8 @@ Run using a Macbook pro with M1 pro chipset running macOS Sonoma 14.4.1 and home
5353
| 102,132
5454
| 16.367
5555
| `decimal128_fast`
56-
| 1,427,647
57-
| 228.790
56+
| 146,302
57+
| 23.446
5858
|===
5959

6060
== Basic Operations
@@ -92,8 +92,8 @@ Run using a Macbook pro with M1 pro chipset running macOS Sonoma 14.4.1 and home
9292
| 139,294
9393
| 44.248
9494
| `decimal128_fast`
95-
| 1,351,882
96-
| 429.442
95+
| 707,308
96+
| 224.685
9797
|===
9898

9999
==== Subtraction
@@ -122,8 +122,8 @@ Run using a Macbook pro with M1 pro chipset running macOS Sonoma 14.4.1 and home
122122
| 145,606
123123
| 87.820
124124
| `decimal128_fast`
125-
| 894,695
126-
| 539.623
125+
| 394,538
126+
| 2387.960
127127
|===
128128

129129
==== Multiplication
@@ -152,8 +152,8 @@ Run using a Macbook pro with M1 pro chipset running macOS Sonoma 14.4.1 and home
152152
| 333,582
153153
| 193.943
154154
| `decimal128_fast`
155-
| 1,822,921
156-
| 1059.838
155+
| 1,269,429
156+
| 738.040
157157
|===
158158

159159
==== Division
@@ -182,8 +182,8 @@ Run using a Macbook pro with M1 pro chipset running macOS Sonoma 14.4.1 and home
182182
| 291,671
183183
| 75.289
184184
| `decimal128_fast`
185-
| 292,556
186-
| 75.518
185+
| 302,003
186+
| 77.956
187187
|===
188188

189189
== Selected Special Functions

include/boost/decimal/decimal128_fast.hpp

Lines changed: 40 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -351,50 +351,34 @@ template <typename T1, typename T2, std::enable_if_t<detail::is_integral_v<T1> &
351351
#endif
352352
constexpr decimal128_fast::decimal128_fast(T1 coeff, T2 exp, bool sign) noexcept
353353
{
354+
// Older compilers have issues with conversions from __uint128, so we skip all that and use our uint128
355+
#if defined(BOOST_DECIMAL_HAS_INT128) && (!defined(__GNUC__) || (defined(__GNUC__) && !defined(__clang__) && __GNUC__ < 10)) && (!defined(__clang__) || (defined(__clang__) && __clang_major__ < 13))
356+
using Unsigned_Integer_1 = detail::make_unsigned_t<T1>;
357+
using Unsigned_Integer = std::conditional_t<std::is_same<Unsigned_Integer_1, detail::uint128_t>::value, detail::uint128, Unsigned_Integer_1>;
358+
#else
354359
using Unsigned_Integer = detail::make_unsigned_t<T1>;
360+
#endif
361+
362+
using Basis_Unsigned_Integer = std::conditional_t<std::numeric_limits<Unsigned_Integer>::digits10 < std::numeric_limits<significand_type>::digits10, significand_type, Unsigned_Integer>;
355363

356364
const bool isneg {coeff < static_cast<T1>(0) || sign};
357365
sign_ = isneg;
358-
Unsigned_Integer unsigned_coeff {detail::make_positive_unsigned(coeff)};
359-
360-
auto unsigned_coeff_digits {detail::num_digits(unsigned_coeff)};
361-
const bool reduced {unsigned_coeff_digits > detail::precision_v<decimal128>};
362-
363-
// Strip digits
364-
if (unsigned_coeff_digits > detail::precision_v<decimal128> + 1)
365-
{
366-
const auto digits_to_remove {unsigned_coeff_digits - (detail::precision_v<decimal128> + 1)};
367-
368-
#if defined(__GNUC__) && !defined(__clang__)
369-
# pragma GCC diagnostic push
370-
# pragma GCC diagnostic ignored "-Wconversion"
371-
#endif
372-
373-
unsigned_coeff /= detail::pow10(static_cast<Unsigned_Integer>(digits_to_remove));
374-
375-
#if defined(__GNUC__) && !defined(__clang__)
376-
# pragma GCC diagnostic pop
377-
#endif
378-
379-
exp += digits_to_remove;
380-
unsigned_coeff_digits -= digits_to_remove;
381-
}
366+
auto unsigned_coeff {static_cast<Basis_Unsigned_Integer>(detail::make_positive_unsigned(coeff))};
382367

383-
// Round as required
384-
if (reduced)
385-
{
386-
exp += static_cast<T2>(detail::fenv_round(unsigned_coeff, isneg));
387-
}
368+
// Normalize the significand in the constructor, so we don't have
369+
// to calculate the number of digits for operationss
370+
detail::normalize<decimal128>(unsigned_coeff, exp, sign);
388371

389-
significand_ = static_cast<significand_type>(unsigned_coeff);
372+
significand_ = unsigned_coeff;
390373

391-
// Normalize the handling of zeros
374+
// Normalize the handling of 0
392375
if (significand_ == detail::uint128{UINT64_C(0), UINT64_C(0)})
393376
{
394377
exp = 0;
395378
}
396379

397380
const auto biased_exp {static_cast<exponent_type>(exp + detail::bias_v<decimal128>)};
381+
398382
if (biased_exp > detail::max_biased_exp_v<decimal128>)
399383
{
400384
significand_ = detail::d128_fast_inf;
@@ -504,8 +488,9 @@ constexpr auto operator==(const decimal128_fast& lhs, const decimal128_fast& rhs
504488
}
505489
#endif
506490

507-
return equal_parts_impl(lhs.significand_, lhs.biased_exponent(), lhs.sign_,
508-
rhs.significand_, rhs.biased_exponent(), rhs.sign_);
491+
return lhs.sign_ == rhs.sign_ &&
492+
lhs.exponent_ == rhs.exponent_ &&
493+
lhs.significand_ == rhs.significand_;
509494
}
510495

511496
template <typename Integer>
@@ -572,8 +557,17 @@ constexpr auto operator<(const decimal128_fast& lhs, const decimal128_fast& rhs)
572557
}
573558
#endif
574559

575-
return less_parts_impl<decimal128>(lhs.significand_, lhs.biased_exponent(), lhs.sign_,
576-
rhs.significand_, rhs.biased_exponent(), rhs.sign_);
560+
if (lhs.significand_ == 0 || rhs.significand_ == 0)
561+
{
562+
return lhs.significand_ == 0 ? !rhs.sign_ : lhs.sign_;
563+
}
564+
565+
if (lhs.exponent_ != rhs.exponent_)
566+
{
567+
return lhs.sign_ ? lhs.exponent_ > rhs.exponent_ : lhs.exponent_ < rhs.exponent_;
568+
}
569+
570+
return lhs.sign_ ? lhs.significand_ > rhs.significand_ : lhs.significand_ < rhs.significand_;
577571
}
578572

579573
template <typename Integer>
@@ -798,17 +792,9 @@ constexpr auto operator+(decimal128_fast lhs, decimal128_fast rhs) noexcept -> d
798792
return lhs - abs(rhs);
799793
}
800794

801-
auto lhs_sig {lhs.full_significand()};
802-
auto lhs_exp {lhs.biased_exponent()};
803-
detail::normalize<decimal128>(lhs_sig, lhs_exp);
804-
805-
auto rhs_sig {rhs.full_significand()};
806-
auto rhs_exp {rhs.biased_exponent()};
807-
detail::normalize<decimal128>(rhs_sig, rhs_exp);
808-
809795
const auto result {detail::d128_add_impl<detail::decimal128_fast_components>(
810-
lhs_sig, lhs_exp, lhs.sign_,
811-
rhs_sig, rhs_exp, rhs.sign_)};
796+
lhs.significand_, lhs.biased_exponent(), lhs.sign_,
797+
rhs.significand_, rhs.biased_exponent(), rhs.sign_)};
812798

813799
return {result.sig, result.exp, result.sign};
814800
};
@@ -831,10 +817,7 @@ constexpr auto operator+(decimal128_fast lhs, Integer rhs) noexcept
831817
}
832818
bool abs_lhs_bigger {abs(lhs) > detail::make_positive_unsigned(rhs)};
833819

834-
auto sig_lhs {lhs.full_significand()};
835-
auto exp_lhs {lhs.biased_exponent()};
836-
detail::normalize<decimal128>(sig_lhs, exp_lhs);
837-
auto lhs_components {detail::decimal128_fast_components{sig_lhs, exp_lhs, lhs.isneg()}};
820+
auto lhs_components {detail::decimal128_fast_components{lhs.significand_, lhs.biased_exponent(), lhs.isneg()}};
838821

839822
auto sig_rhs {static_cast<detail::uint128>(detail::make_positive_unsigned(rhs))};
840823
std::int32_t exp_rhs {0};
@@ -901,17 +884,9 @@ constexpr auto operator-(decimal128_fast lhs, decimal128_fast rhs) noexcept -> d
901884

902885
const bool abs_lhs_bigger {abs(lhs) > abs(rhs)};
903886

904-
auto sig_lhs {lhs.full_significand()};
905-
auto exp_lhs {lhs.biased_exponent()};
906-
detail::normalize<decimal128>(sig_lhs, exp_lhs);
907-
908-
auto sig_rhs {rhs.full_significand()};
909-
auto exp_rhs {rhs.biased_exponent()};
910-
detail::normalize<decimal128>(sig_rhs, exp_rhs);
911-
912887
const auto result {detail::d128_sub_impl<detail::decimal128_fast_components>(
913-
sig_lhs, exp_lhs, lhs.sign_,
914-
sig_rhs, exp_rhs, rhs.sign_,
888+
lhs.significand_, lhs.biased_exponent(), lhs.sign_,
889+
rhs.significand_, rhs.biased_exponent(), rhs.sign_,
915890
abs_lhs_bigger
916891
)};
917892

@@ -936,10 +911,7 @@ constexpr auto operator-(decimal128_fast lhs, Integer rhs) noexcept
936911

937912
const bool abs_lhs_bigger {abs(lhs) > detail::make_positive_unsigned(rhs)};
938913

939-
auto sig_lhs {lhs.full_significand()};
940-
auto exp_lhs {lhs.biased_exponent()};
941-
detail::normalize<decimal128>(sig_lhs, exp_lhs);
942-
auto lhs_components {detail::decimal128_fast_components{sig_lhs, exp_lhs, lhs.isneg()}};
914+
auto lhs_components {detail::decimal128_fast_components{lhs.significand_, lhs.biased_exponent(), lhs.isneg()}};
943915

944916
auto sig_rhs {static_cast<detail::uint128>(detail::make_positive_unsigned(rhs))};
945917
std::int32_t exp_rhs {0};
@@ -979,10 +951,7 @@ constexpr auto operator-(Integer lhs, decimal128_fast rhs) noexcept
979951
auto unsigned_sig_lhs {detail::make_positive_unsigned(sig_lhs)};
980952
auto lhs_components {detail::decimal128_fast_components{unsigned_sig_lhs, exp_lhs, (lhs < 0)}};
981953

982-
auto sig_rhs {rhs.full_significand()};
983-
auto exp_rhs {rhs.biased_exponent()};
984-
detail::normalize<decimal128>(sig_rhs, exp_rhs);
985-
auto rhs_components {detail::decimal128_fast_components{sig_rhs, exp_rhs, rhs.isneg()}};
954+
auto rhs_components {detail::decimal128_fast_components{rhs.significand_, rhs.biased_exponent(), rhs.isneg()}};
986955

987956
const auto result {detail::d128_sub_impl<detail::decimal128_fast_components>(
988957
lhs_components.sig, lhs_components.exp, lhs_components.sign,
@@ -1115,23 +1084,15 @@ constexpr auto d128f_div_impl(decimal128_fast lhs, decimal128_fast rhs, decimal1
11151084
static_cast<void>(r);
11161085
#endif
11171086

1118-
auto sig_lhs {lhs.full_significand()};
1119-
auto exp_lhs {lhs.biased_exponent()};
1120-
detail::normalize<decimal128>(sig_lhs, exp_lhs);
1121-
1122-
auto sig_rhs {rhs.full_significand()};
1123-
auto exp_rhs {rhs.biased_exponent()};
1124-
detail::normalize<decimal128>(sig_rhs, exp_rhs);
1125-
11261087
#ifdef BOOST_DECIMAL_DEBUG
11271088
std::cerr << "sig lhs: " << sig_lhs
11281089
<< "\nexp lhs: " << exp_lhs
11291090
<< "\nsig rhs: " << sig_rhs
11301091
<< "\nexp rhs: " << exp_rhs << std::endl;
11311092
#endif
11321093

1133-
detail::decimal128_fast_components lhs_components {sig_lhs, exp_lhs, lhs.isneg()};
1134-
detail::decimal128_fast_components rhs_components {sig_rhs, exp_rhs, rhs.isneg()};
1094+
detail::decimal128_fast_components lhs_components {lhs.significand_, lhs.biased_exponent(), lhs.isneg()};
1095+
detail::decimal128_fast_components rhs_components {rhs.significand_, rhs.biased_exponent(), rhs.isneg()};
11351096
detail::decimal128_fast_components q_components {};
11361097

11371098
detail::d128_generic_div_impl(lhs_components, rhs_components, q_components);
@@ -1188,11 +1149,7 @@ constexpr auto operator/(decimal128_fast lhs, Integer rhs) noexcept
11881149
}
11891150
#endif
11901151

1191-
auto lhs_sig {lhs.full_significand()};
1192-
auto lhs_exp {lhs.biased_exponent()};
1193-
detail::normalize<decimal128>(lhs_sig, lhs_exp);
1194-
1195-
detail::decimal128_fast_components lhs_components {lhs_sig, lhs_exp, lhs.isneg()};
1152+
detail::decimal128_fast_components lhs_components {lhs.significand_, lhs.biased_exponent(), lhs.isneg()};
11961153

11971154
auto rhs_sig {detail::make_positive_unsigned(rhs)};
11981155
std::int32_t rhs_exp {};
@@ -1234,12 +1191,8 @@ constexpr auto operator/(Integer lhs, decimal128_fast rhs) noexcept
12341191
}
12351192
#endif
12361193

1237-
auto rhs_sig {rhs.full_significand()};
1238-
auto rhs_exp {rhs.biased_exponent()};
1239-
detail::normalize<decimal128>(rhs_sig, rhs_exp);
1240-
12411194
detail::decimal128_fast_components lhs_components {detail::make_positive_unsigned(lhs), 0, lhs < 0};
1242-
detail::decimal128_fast_components rhs_components {rhs_sig, rhs_exp, rhs.isneg()};
1195+
detail::decimal128_fast_components rhs_components {rhs.significand_, rhs.biased_exponent(), rhs.isneg()};
12431196
detail::decimal128_fast_components q_components {};
12441197

12451198
detail::d128_generic_div_impl(lhs_components, rhs_components, q_components);

include/boost/decimal/detail/add_impl.hpp

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -220,24 +220,23 @@ constexpr auto d128_add_impl(T1 lhs_sig, std::int32_t lhs_exp, bool lhs_sign,
220220
{
221221
lhs_sig *= detail::pow10(static_cast<detail::uint128>(delta_exp));
222222
lhs_exp -= delta_exp;
223-
delta_exp = 0;
224223
}
225224
else
226225
{
227226
lhs_sig *= 1000;
228227
delta_exp -= 3;
229228
lhs_exp -= 3;
230-
}
231229

232-
while (delta_exp > 1)
233-
{
234-
rhs_sig /= detail::pow10(static_cast<detail::uint128>(delta_exp - 1));
235-
delta_exp = 1;
236-
}
230+
if (delta_exp > 1)
231+
{
232+
rhs_sig /= pow10(static_cast<uint128>(delta_exp - 1));
233+
delta_exp = 1;
234+
}
237235

238-
if (delta_exp == 1)
239-
{
240-
detail::fenv_round<decimal128>(rhs_sig, rhs_sign);
236+
if (delta_exp == 1)
237+
{
238+
detail::fenv_round<decimal128>(rhs_sig, rhs_sign);
239+
}
241240
}
242241

243242
const auto new_sig {static_cast<typename ReturnType::sig_type>(lhs_sig) +

0 commit comments

Comments
 (0)