Skip to content

Commit efa23ba

Browse files
authored
Merge pull request #912 from cppalliance/906
Improve `decimal128_fast` multiplication performance
2 parents fd8b26f + 1a21540 commit efa23ba

File tree

9 files changed

+54
-187
lines changed

9 files changed

+54
-187
lines changed

include/boost/decimal/decimal128.hpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -365,7 +365,7 @@ BOOST_DECIMAL_EXPORT class decimal128 final
365365
friend constexpr auto operator-(Integer lhs, decimal128 rhs) noexcept
366366
BOOST_DECIMAL_REQUIRES_RETURN(detail::is_integral_v, Integer, decimal128);
367367

368-
friend constexpr auto operator*(decimal128 lhs, decimal128 rhs) noexcept -> decimal128;
368+
friend constexpr auto operator*(const decimal128& lhs, const decimal128& rhs) noexcept -> decimal128;
369369

370370
template <typename Integer>
371371
friend constexpr auto operator*(decimal128 lhs, Integer rhs) noexcept
@@ -671,7 +671,7 @@ constexpr auto decimal128::full_significand() const noexcept -> int128::uint128_
671671
{
672672
// Last three bits in the combination field, so we need to shift past the exp field
673673
// which is next. Only need to operate on the high bits
674-
significand.high |= (bits_.high & detail::d128_comb_00_01_10_significand_bits.high) >> detail::d128_exponent_bits;
674+
significand.high = (bits_.high & detail::d128_comb_00_01_10_significand_bits.high) >> detail::d128_exponent_bits;
675675
}
676676

677677
significand |= (bits_ & detail::d128_significand_mask);
@@ -1230,7 +1230,7 @@ constexpr auto isfinite BOOST_DECIMAL_PREVENT_MACRO_SUBSTITUTION (decimal128 rhs
12301230
#endif
12311231
}
12321232

1233-
constexpr auto not_finite(decimal128 rhs) noexcept -> bool
1233+
BOOST_DECIMAL_FORCE_INLINE constexpr auto not_finite(decimal128 rhs) noexcept -> bool
12341234
{
12351235
#ifndef BOOST_DECIMAL_FAST_MATH
12361236
return (rhs.bits_.high & detail::d128_inf_mask_high_bits) == detail::d128_inf_mask_high_bits;
@@ -1755,7 +1755,7 @@ constexpr auto operator-(Integer lhs, decimal128 rhs) noexcept
17551755
abs_lhs_bigger);
17561756
}
17571757

1758-
constexpr auto operator*(decimal128 lhs, decimal128 rhs) noexcept -> decimal128
1758+
constexpr auto operator*(const decimal128& lhs, const decimal128& rhs) noexcept -> decimal128
17591759
{
17601760
#ifndef BOOST_DECIMAL_FAST_MATH
17611761
if (not_finite(lhs) || not_finite(rhs))

include/boost/decimal/decimal128_fast.hpp

Lines changed: 20 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ BOOST_DECIMAL_EXPORT class decimal128_fast final
8686
template <BOOST_DECIMAL_DECIMAL_FLOATING_TYPE TargetType, BOOST_DECIMAL_DECIMAL_FLOATING_TYPE Decimal>
8787
friend constexpr auto to_decimal(Decimal val) noexcept -> TargetType;
8888

89-
friend constexpr auto d128f_div_impl(decimal128_fast lhs, decimal128_fast rhs, decimal128_fast& q, decimal128_fast& r) noexcept -> void;
89+
friend constexpr auto d128f_div_impl(const decimal128_fast& lhs, const decimal128_fast& rhs, decimal128_fast& q, decimal128_fast& r) noexcept -> void;
9090

9191
// Equality template between any integer type and decimal128
9292
template <BOOST_DECIMAL_DECIMAL_FLOATING_TYPE Decimal, BOOST_DECIMAL_INTEGRAL Integer>
@@ -242,11 +242,11 @@ BOOST_DECIMAL_EXPORT class decimal128_fast final
242242
friend constexpr auto operator-(decimal128_fast rhs) noexcept -> decimal128_fast;
243243

244244
// Binary arithmetic operators
245-
friend constexpr auto operator+(decimal128_fast lhs, decimal128_fast rhs) noexcept -> decimal128_fast;
246-
friend constexpr auto operator-(decimal128_fast lhs, decimal128_fast rhs) noexcept -> decimal128_fast;
247-
friend constexpr auto operator*(decimal128_fast lhs, decimal128_fast rhs) noexcept -> decimal128_fast;
248-
friend constexpr auto operator/(decimal128_fast lhs, decimal128_fast rhs) noexcept -> decimal128_fast;
249-
friend constexpr auto operator%(decimal128_fast lhs, decimal128_fast rhs) noexcept -> decimal128_fast;
245+
friend constexpr auto operator+(const decimal128_fast& lhs, const decimal128_fast& rhs) noexcept -> decimal128_fast;
246+
friend constexpr auto operator-(const decimal128_fast& lhs, const decimal128_fast& rhs) noexcept -> decimal128_fast;
247+
friend constexpr auto operator*(const decimal128_fast& lhs, const decimal128_fast& rhs) noexcept -> decimal128_fast;
248+
friend constexpr auto operator/(const decimal128_fast& lhs, const decimal128_fast& rhs) noexcept -> decimal128_fast;
249+
friend constexpr auto operator%(const decimal128_fast& lhs, const decimal128_fast& rhs) noexcept -> decimal128_fast;
250250

251251
// Mixed type binary arithmetic operators
252252
template <typename Integer>
@@ -355,13 +355,13 @@ BOOST_DECIMAL_EXPORT class decimal128_fast final
355355

356356
// Decimal functions
357357
// 3.6.4 Same Quantum
358-
friend constexpr auto samequantumd128f(decimal128_fast lhs, decimal128_fast rhs) noexcept -> bool;
358+
friend constexpr auto samequantumd128f(const decimal128_fast& lhs, const decimal128_fast& rhs) noexcept -> bool;
359359

360360
// 3.6.5 Quantum exponent
361361
friend constexpr auto quantexpd128f(decimal128_fast x) noexcept -> int;
362362

363363
// 3.6.6 Quantize
364-
friend constexpr auto quantized128f(decimal128_fast lhs, decimal128_fast rhs) noexcept -> decimal128_fast;
364+
friend constexpr auto quantized128f(const decimal128_fast& lhs, const decimal128_fast& rhs) noexcept -> decimal128_fast;
365365
};
366366

367367
#ifdef BOOST_DECIMAL_HAS_CONCEPTS
@@ -526,7 +526,7 @@ constexpr auto isfinite(decimal128_fast val) noexcept -> bool
526526
#endif
527527
}
528528

529-
constexpr auto not_finite(const decimal128_fast& val) noexcept -> bool
529+
BOOST_DECIMAL_FORCE_INLINE constexpr auto not_finite(const decimal128_fast& val) noexcept -> bool
530530
{
531531
#ifndef BOOST_DECIMAL_FAST_MATH
532532
return val.significand_.high >= detail::d128_fast_inf_high_bits;
@@ -772,7 +772,7 @@ constexpr auto operator-(decimal128_fast rhs) noexcept -> decimal128_fast
772772
return rhs;
773773
}
774774

775-
constexpr auto operator+(decimal128_fast lhs, decimal128_fast rhs) noexcept -> decimal128_fast
775+
constexpr auto operator+(const decimal128_fast& lhs, const decimal128_fast& rhs) noexcept -> decimal128_fast
776776
{
777777
#ifndef BOOST_DECIMAL_FAST_MATH
778778
if (not_finite(lhs) || not_finite(rhs))
@@ -818,7 +818,7 @@ constexpr auto operator+(Integer lhs, decimal128_fast rhs) noexcept
818818
return rhs + lhs;
819819
}
820820

821-
constexpr auto operator-(decimal128_fast lhs, decimal128_fast rhs) noexcept -> decimal128_fast
821+
constexpr auto operator-(const decimal128_fast& lhs, const decimal128_fast& rhs) noexcept -> decimal128_fast
822822
{
823823
#ifndef BOOST_DECIMAL_FAST_MATH
824824
if (not_finite(lhs) || not_finite(rhs))
@@ -883,7 +883,7 @@ constexpr auto operator-(Integer lhs, decimal128_fast rhs) noexcept
883883
abs_lhs_bigger);
884884
}
885885

886-
constexpr auto operator*(decimal128_fast lhs, decimal128_fast rhs) noexcept -> decimal128_fast
886+
constexpr auto operator*(const decimal128_fast& lhs, const decimal128_fast& rhs) noexcept -> decimal128_fast
887887
{
888888
#ifndef BOOST_DECIMAL_FAST_MATH
889889
if (not_finite(lhs) || not_finite(rhs))
@@ -892,21 +892,8 @@ constexpr auto operator*(decimal128_fast lhs, decimal128_fast rhs) noexcept -> d
892892
}
893893
#endif
894894

895-
auto lhs_sig {lhs.full_significand()};
896-
auto lhs_exp {lhs.biased_exponent()};
897-
const auto lhs_zeros {detail::remove_trailing_zeros(lhs_sig)};
898-
lhs_sig = lhs_zeros.trimmed_number;
899-
lhs_exp += static_cast<std::int32_t>(lhs_zeros.number_of_removed_zeros);
900-
901-
auto rhs_sig {rhs.full_significand()};
902-
auto rhs_exp {rhs.biased_exponent()};
903-
const auto rhs_zeros {detail::remove_trailing_zeros(rhs_sig)};
904-
rhs_sig = rhs_zeros.trimmed_number;
905-
rhs_exp += static_cast<std::int32_t>(rhs_zeros.number_of_removed_zeros);
906-
907-
return detail::d128_mul_impl<decimal128_fast>(
908-
lhs_sig, lhs_exp, lhs.sign_,
909-
rhs_sig, rhs_exp, rhs.sign_);
895+
return detail::d128_mul_impl<decimal128_fast>(lhs.significand_, lhs.biased_exponent(), lhs.sign_,
896+
rhs.significand_, rhs.biased_exponent(), rhs.sign_);
910897
}
911898

912899
template <typename Integer>
@@ -938,7 +925,7 @@ constexpr auto operator*(Integer lhs, decimal128_fast rhs) noexcept
938925
return rhs * lhs;
939926
}
940927

941-
constexpr auto d128f_div_impl(decimal128_fast lhs, decimal128_fast rhs, decimal128_fast& q, decimal128_fast& r) noexcept -> void
928+
constexpr auto d128f_div_impl(const decimal128_fast& lhs, const decimal128_fast& rhs, decimal128_fast& q, decimal128_fast& r) noexcept -> void
942929
{
943930
#ifndef BOOST_DECIMAL_FAST_MATH
944931
// Check pre-conditions
@@ -1005,15 +992,15 @@ constexpr auto d128f_div_impl(decimal128_fast lhs, decimal128_fast rhs, decimal1
1005992
q = decimal128_fast(q_components.sig, q_components.exp, q_components.sign);
1006993
}
1007994

1008-
constexpr auto d128f_mod_impl(decimal128_fast lhs, decimal128_fast rhs, const decimal128_fast& q, decimal128_fast& r) -> void
995+
constexpr auto d128f_mod_impl(const decimal128_fast& lhs, const decimal128_fast& rhs, const decimal128_fast& q, decimal128_fast& r) -> void
1009996
{
1010997
constexpr decimal128_fast zero {0, 0};
1011998

1012999
auto q_trunc {q > zero ? floor(q) : ceil(q)};
10131000
r = lhs - (decimal128_fast(q_trunc) * rhs);
10141001
};
10151002

1016-
constexpr auto operator/(decimal128_fast lhs, decimal128_fast rhs) noexcept -> decimal128_fast
1003+
constexpr auto operator/(const decimal128_fast& lhs, const decimal128_fast& rhs) noexcept -> decimal128_fast
10171004
{
10181005
decimal128_fast q {};
10191006
decimal128_fast r {};
@@ -1104,7 +1091,7 @@ constexpr auto operator/(Integer lhs, decimal128_fast rhs) noexcept
11041091
return {q_components.sig, q_components.exp, q_components.sign};
11051092
}
11061093

1107-
constexpr auto operator%(decimal128_fast lhs, decimal128_fast rhs) noexcept -> decimal128_fast
1094+
constexpr auto operator%(const decimal128_fast& lhs, const decimal128_fast& rhs) noexcept -> decimal128_fast
11081095
{
11091096
decimal128_fast q {};
11101097
decimal128_fast r {};
@@ -1318,7 +1305,7 @@ constexpr auto scalbnd128f(decimal128_fast num, int exp) noexcept -> decimal128_
13181305
// If both x and y are NaN, or infinity, they have the same quantum exponents;
13191306
// if exactly one operand is infinity or exactly one operand is NaN, they do not have the same quantum exponents.
13201307
// The samequantum functions raise no exception.
1321-
constexpr auto samequantumd128f(decimal128_fast lhs, decimal128_fast rhs) noexcept -> bool
1308+
constexpr auto samequantumd128f(const decimal128_fast& lhs, const decimal128_fast& rhs) noexcept -> bool
13221309
{
13231310
#ifndef BOOST_DECIMAL_FAST_MATH
13241311
const auto lhs_fp {fpclassify(lhs)};
@@ -1363,7 +1350,7 @@ constexpr auto quantexpd128f(decimal128_fast x) noexcept -> int
13631350
// Otherwise, if only one operand is infinity, the "invalid" floating-point exception is raised and the result is NaN.
13641351
// If both operands are infinity, the result is DEC_INFINITY, with the same sign as x, converted to the type of x.
13651352
// The quantize functions do not signal underflow.
1366-
constexpr auto quantized128f(decimal128_fast lhs, decimal128_fast rhs) noexcept -> decimal128_fast
1353+
constexpr auto quantized128f(const decimal128_fast& lhs, const decimal128_fast& rhs) noexcept -> decimal128_fast
13671354
{
13681355
#ifndef BOOST_DECIMAL_FAST_MATH
13691356
// Return the correct type of nan

include/boost/decimal/decimal32.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1437,7 +1437,7 @@ constexpr auto decimal32::full_significand() const noexcept -> significand_type
14371437
{
14381438
// Last three bits in the combination field, so we need to shift past the exp field
14391439
// which is next
1440-
significand |= (bits_ & detail::d32_comb_00_01_10_significand_bits) >> detail::d32_exponent_bits;
1440+
significand = (bits_ & detail::d32_comb_00_01_10_significand_bits) >> detail::d32_exponent_bits;
14411441
}
14421442

14431443
significand |= (bits_ & detail::d32_significand_mask);

include/boost/decimal/decimal32_fast.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -515,7 +515,7 @@ constexpr auto isfinite(decimal32_fast val) noexcept -> bool
515515
return val.significand_ < detail::d32_fast_inf;
516516
}
517517

518-
constexpr auto not_finite(const decimal32_fast& val) noexcept -> bool
518+
BOOST_DECIMAL_FORCE_INLINE constexpr auto not_finite(const decimal32_fast& val) noexcept -> bool
519519
{
520520
return val.significand_ >= detail::d32_fast_inf;
521521
}

include/boost/decimal/decimal64.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1051,7 +1051,7 @@ constexpr auto decimal64::full_significand() const noexcept -> significand_type
10511051
{
10521052
// Last three bits in the combination field, so we need to shift past the exp field
10531053
// which is next
1054-
significand |= (bits_ & detail::d64_comb_00_01_10_significand_bits) >> detail::d64_exponent_bits;
1054+
significand = (bits_ & detail::d64_comb_00_01_10_significand_bits) >> detail::d64_exponent_bits;
10551055
}
10561056

10571057
significand |= (bits_ & detail::d64_significand_mask);
@@ -1189,7 +1189,7 @@ constexpr auto isfinite BOOST_DECIMAL_PREVENT_MACRO_SUBSTITUTION (decimal64 rhs)
11891189
#endif
11901190
}
11911191

1192-
constexpr auto not_finite(decimal64 rhs) noexcept -> bool
1192+
BOOST_DECIMAL_FORCE_INLINE constexpr auto not_finite(decimal64 rhs) noexcept -> bool
11931193
{
11941194
#ifndef BOOST_DECIMAL_FAST_MATH
11951195
return ((rhs.bits_ & detail::d64_inf_mask) == detail::d64_inf_mask);

include/boost/decimal/decimal64_fast.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -539,7 +539,7 @@ constexpr auto isfinite(decimal64_fast val) noexcept -> bool
539539
return val.significand_ < detail::d64_fast_inf;
540540
}
541541

542-
constexpr auto not_finite(decimal64_fast val) noexcept -> bool
542+
BOOST_DECIMAL_FORCE_INLINE constexpr auto not_finite(decimal64_fast val) noexcept -> bool
543543
{
544544
return val.significand_ >= detail::d64_fast_inf;
545545
}

include/boost/decimal/detail/add_impl.hpp

Lines changed: 7 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ constexpr auto d32_add_impl(const T& lhs, const T& rhs) noexcept -> ReturnType
4242

4343
if (shift > max_shift)
4444
{
45-
return lhs.full_significand() != 0U && (lhs_exp > rhs_exp) ?
45+
return big_lhs != 0U && (lhs_exp > rhs_exp) ?
4646
ReturnType{lhs.full_significand(), lhs.biased_exponent(), lhs.isneg()} :
4747
ReturnType{rhs.full_significand(), rhs.biased_exponent(), rhs.isneg()};
4848
}
@@ -90,7 +90,8 @@ constexpr auto d32_add_impl(T lhs_sig, U lhs_exp, bool lhs_sign,
9090
{
9191
return lhs_sig != 0U && (lhs_exp > rhs_exp) ? ReturnType{lhs_sig, lhs_exp, lhs_sign} : ReturnType{rhs_sig, rhs_exp, rhs_sign};
9292
}
93-
else if (lhs_exp < rhs_exp)
93+
94+
if (lhs_exp < rhs_exp)
9495
{
9596
big_rhs *= detail::pow10<promoted_sig_type>(shift);
9697
lhs_exp = rhs_exp - static_cast<U>(shift);
@@ -111,79 +112,6 @@ constexpr auto d32_add_impl(T lhs_sig, U lhs_exp, bool lhs_sign,
111112
return {new_sig, lhs_exp};
112113
}
113114

114-
template <typename ReturnType, typename T, typename U>
115-
BOOST_DECIMAL_FORCE_INLINE constexpr auto add_impl(T lhs_sig, U lhs_exp, bool lhs_sign,
116-
T rhs_sig, U rhs_exp, bool rhs_sign) noexcept -> ReturnType
117-
{
118-
const bool sign {lhs_sign};
119-
120-
auto delta_exp {lhs_exp > rhs_exp ? lhs_exp - rhs_exp : rhs_exp - lhs_exp};
121-
122-
#ifdef BOOST_DECIMAL_DEBUG_ADD
123-
std::cerr << "Starting sig lhs: " << lhs_sig
124-
<< "\nStarting exp lhs: " << lhs_exp
125-
<< "\nStarting sig rhs: " << rhs_sig
126-
<< "\nStarting exp rhs: " << rhs_exp << std::endl;
127-
#endif
128-
129-
if (delta_exp > detail::precision + 1)
130-
{
131-
// If the difference in exponents is more than the digits of accuracy
132-
// we return the larger of the two
133-
//
134-
// e.g. 1e20 + 1e-20 = 1e20
135-
136-
#ifdef BOOST_DECIMAL_DEBUG_ADD
137-
std::cerr << "New sig: " << lhs_sig
138-
<< "\nNew exp: " << lhs_exp
139-
<< "\nNew neg: " << lhs_sign << std::endl;
140-
#endif
141-
142-
return {static_cast<std::uint32_t>(lhs_sig), lhs_exp, lhs_sign};
143-
}
144-
145-
// The two numbers can be added together without special handling
146-
//
147-
// If we can add to the lhs sig rather than dividing we can save some precision
148-
// 32-bit signed int can have 9 digits and our normalized significand has 7
149-
if (delta_exp <= 2)
150-
{
151-
lhs_sig *= pow10(static_cast<T>(delta_exp));
152-
lhs_exp -= delta_exp;
153-
delta_exp = 0;
154-
}
155-
else
156-
{
157-
lhs_sig *= 100;
158-
delta_exp -= 2;
159-
lhs_exp -=2;
160-
161-
if (delta_exp > 1)
162-
{
163-
rhs_sig /= pow10(static_cast<T>(delta_exp - 1));
164-
delta_exp = 1;
165-
}
166-
167-
if (delta_exp == 1)
168-
{
169-
detail::fenv_round(rhs_sig, rhs_sign);
170-
}
171-
}
172-
173-
// Cast the results to signed types so that we can apply a sign at the end if necessary
174-
// Both of the significands are maximally 24 bits, so they fit into a 32-bit signed type just fine
175-
const auto new_sig {static_cast<typename ReturnType::significand_type>(lhs_sig + rhs_sig)};
176-
const auto new_exp {lhs_exp};
177-
178-
#ifdef BOOST_DECIMAL_DEBUG_ADD
179-
std::cerr << "Final sig lhs: " << lhs_sig
180-
<< "\nFinal sig rhs: " << rhs_sig
181-
<< "\nResult sig: " << new_sig << std::endl;
182-
#endif
183-
184-
return {new_sig, new_exp, sign};
185-
}
186-
187115
template <typename ReturnType, typename T>
188116
constexpr auto d64_add_impl(const T& lhs, const T& rhs) noexcept -> ReturnType
189117
{
@@ -210,7 +138,8 @@ constexpr auto d64_add_impl(const T& lhs, const T& rhs) noexcept -> ReturnType
210138
ReturnType{lhs.full_significand(), lhs.biased_exponent(), lhs.isneg()} :
211139
ReturnType{rhs.full_significand(), rhs.biased_exponent(), rhs.isneg()};
212140
}
213-
else if (lhs_exp < rhs_exp)
141+
142+
if (lhs_exp < rhs_exp)
214143
{
215144
big_rhs *= detail::pow10<promoted_sig_type>(shift);
216145
lhs_exp = rhs_exp - static_cast<decimal64_components::biased_exponent_type>(shift);
@@ -333,7 +262,8 @@ constexpr auto d128_add_impl(T1 lhs_sig, U1 lhs_exp, bool lhs_sign,
333262

334263
return {lhs_sig, lhs_exp, lhs_sign};
335264
}
336-
else if (delta_exp == detail::precision_v<decimal128> + 1)
265+
266+
if (delta_exp == detail::precision_v<decimal128> + 1)
337267
{
338268
// Only need to see if we need to add one to the
339269
// significand of the bigger value

0 commit comments

Comments
 (0)