Skip to content

Commit 04f5974

Browse files
authored
Merge pull request #573 from cppalliance/stl_fast
Begin binding STL functions for decimal32_fast
2 parents 6899538 + 7273ff1 commit 04f5974

File tree

12 files changed

+133
-77
lines changed

12 files changed

+133
-77
lines changed

include/boost/decimal/charconv.hpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,11 @@ BOOST_DECIMAL_EXPORT constexpr auto from_chars(const char* first, const char* la
9393
return detail::from_chars_general_impl(first, last, value, fmt);
9494
}
9595

96+
BOOST_DECIMAL_EXPORT constexpr auto from_chars(const char* first, const char* last, decimal32_fast& value, chars_format fmt = chars_format::general) noexcept
97+
{
98+
return detail::from_chars_general_impl(first, last, value, fmt);
99+
}
100+
96101
BOOST_DECIMAL_EXPORT constexpr auto from_chars(const char* first, const char* last, decimal64& value, chars_format fmt = chars_format::general) noexcept
97102
{
98103
return detail::from_chars_general_impl(first, last, value, fmt);
@@ -778,6 +783,26 @@ BOOST_DECIMAL_EXPORT BOOST_DECIMAL_CONSTEXPR auto to_chars(char* first, char* la
778783
return detail::to_chars_impl(first, last, value, fmt, precision);
779784
}
780785

786+
BOOST_DECIMAL_EXPORT BOOST_DECIMAL_CONSTEXPR auto to_chars(char* first, char* last, decimal32_fast value) noexcept -> to_chars_result
787+
{
788+
return detail::to_chars_impl(first, last, value);
789+
}
790+
791+
BOOST_DECIMAL_EXPORT BOOST_DECIMAL_CONSTEXPR auto to_chars(char* first, char* last, decimal32_fast value, chars_format fmt) noexcept -> to_chars_result
792+
{
793+
return detail::to_chars_impl(first, last, value, fmt);
794+
}
795+
796+
BOOST_DECIMAL_EXPORT BOOST_DECIMAL_CONSTEXPR auto to_chars(char* first, char* last, decimal32_fast value, chars_format fmt, int precision) noexcept -> to_chars_result
797+
{
798+
if (precision < 0)
799+
{
800+
precision = 6;
801+
}
802+
803+
return detail::to_chars_impl(first, last, value, fmt, precision);
804+
}
805+
781806
BOOST_DECIMAL_EXPORT BOOST_DECIMAL_CONSTEXPR auto to_chars(char* first, char* last, decimal64 value) noexcept -> to_chars_result
782807
{
783808
return detail::to_chars_impl(first, last, value);

include/boost/decimal/decimal128.hpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,9 @@ struct decimal128_components
142142

143143
BOOST_DECIMAL_EXPORT class decimal128 final
144144
{
145+
public:
146+
using significand_type = detail::uint128;
147+
145148
private:
146149
detail::uint128 bits_ {};
147150

@@ -575,10 +578,7 @@ BOOST_DECIMAL_EXPORT class decimal128 final
575578

576579
// <cmath> functions that need to be friends
577580
template <BOOST_DECIMAL_DECIMAL_FLOATING_TYPE T>
578-
friend constexpr auto frexp10(T num, int* expptr) noexcept
579-
-> std::enable_if_t<detail::is_decimal_floating_point_v<T>,
580-
std::conditional_t<std::is_same<T, decimal32>::value, std::uint32_t,
581-
std::conditional_t<std::is_same<T, decimal64>::value, std::uint64_t, detail::uint128>>>;
581+
friend constexpr auto frexp10(T num, int* expptr) noexcept -> typename T::significand_type;
582582

583583
friend constexpr auto copysignd128(decimal128 mag, decimal128 sgn) noexcept -> decimal128;
584584
friend constexpr auto scalblnd128(decimal128 num, long exp) noexcept -> decimal128;

include/boost/decimal/decimal32.hpp

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,9 @@ struct decimal32_components
134134
// 3.2.2 class decimal32
135135
BOOST_DECIMAL_EXPORT class decimal32 final // NOLINT(cppcoreguidelines-special-member-functions,hicpp-special-member-functions)
136136
{
137+
public:
138+
using significand_type = std::uint32_t;
139+
137140
private:
138141

139142
std::uint32_t bits_ {};
@@ -561,10 +564,7 @@ BOOST_DECIMAL_EXPORT class decimal32 final // NOLINT(cppcoreguidelines-special-m
561564

562565
// Related to <cmath>
563566
template <BOOST_DECIMAL_DECIMAL_FLOATING_TYPE T>
564-
friend constexpr auto frexp10(T num, int* expptr) noexcept
565-
-> std::enable_if_t<detail::is_decimal_floating_point_v<T>,
566-
std::conditional_t<std::is_same<T, decimal32>::value, std::uint32_t,
567-
std::conditional_t<std::is_same<T, decimal64>::value, std::uint64_t, detail::uint128>>>;
567+
friend constexpr auto frexp10(T num, int* expptr) noexcept -> typename T::significand_type;
568568

569569
friend constexpr auto scalbnd32(decimal32 num, int exp) noexcept -> decimal32;
570570
friend constexpr auto scalblnd32(decimal32 num, long exp) noexcept -> decimal32;
@@ -848,7 +848,7 @@ constexpr auto add_impl(T lhs_sig, std::int32_t lhs_exp, bool lhs_sign,
848848
<< "\nNew neg: " << lhs_sign << std::endl;
849849
#endif
850850

851-
return {lhs_sig, lhs_exp, lhs_sign};
851+
return {static_cast<std::uint32_t>(lhs_sig), lhs_exp, lhs_sign};
852852
}
853853
else if (delta_exp == detail::precision + 1)
854854
{
@@ -868,7 +868,7 @@ constexpr auto add_impl(T lhs_sig, std::int32_t lhs_exp, bool lhs_sign,
868868
<< "\nNew neg: " << lhs_sign << std::endl;
869869
#endif
870870

871-
return {lhs_sig, lhs_exp, lhs_sign};
871+
return {static_cast<std::uint32_t>(lhs_sig), lhs_exp, lhs_sign};
872872
}
873873

874874
// The two numbers can be added together without special handling
@@ -974,11 +974,11 @@ constexpr auto sub_impl(T lhs_sig, std::int32_t lhs_exp, bool lhs_sign,
974974

975975
if (rhs_sign && !lhs_sign)
976976
{
977-
new_sig = signed_sig_lhs + signed_sig_rhs;
977+
new_sig = static_cast<std::int32_t>(signed_sig_lhs) + static_cast<std::int32_t>(signed_sig_rhs);
978978
}
979979
else
980980
{
981-
new_sig = signed_sig_lhs - signed_sig_rhs;
981+
new_sig = static_cast<std::int32_t>(signed_sig_lhs) - static_cast<std::int32_t>(signed_sig_rhs);
982982
}
983983

984984
const auto new_exp {abs_lhs_bigger ? lhs_exp : rhs_exp};

include/boost/decimal/decimal32_fast.hpp

Lines changed: 64 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -19,33 +19,37 @@ namespace decimal {
1919

2020
namespace detail {
2121

22-
BOOST_DECIMAL_CONSTEXPR_VARIABLE auto d32_fast_inf = std::numeric_limits<std::uint32_t>::max();
23-
BOOST_DECIMAL_CONSTEXPR_VARIABLE auto d32_fast_qnan = std::numeric_limits<std::uint32_t>::max() - 1;
24-
BOOST_DECIMAL_CONSTEXPR_VARIABLE auto d32_fast_snan = std::numeric_limits<std::uint32_t>::max() - 2;
22+
BOOST_DECIMAL_CONSTEXPR_VARIABLE auto d32_fast_inf = std::numeric_limits<std::uint_fast32_t>::max();
23+
BOOST_DECIMAL_CONSTEXPR_VARIABLE auto d32_fast_qnan = std::numeric_limits<std::uint_fast32_t>::max() - 1;
24+
BOOST_DECIMAL_CONSTEXPR_VARIABLE auto d32_fast_snan = std::numeric_limits<std::uint_fast32_t>::max() - 2;
2525

2626
}
2727

2828
class decimal32_fast final
2929
{
30+
public:
31+
using significand_type = std::uint_fast32_t;
32+
3033
private:
3134
// In regular decimal32 we have to decode the 24 bits of the significand and the 8 bits of the exp
32-
// Here we just use them directly at the cost of 2 extra bytes of internal state
35+
// Here we just use them directly at the cost of at least 2 extra bytes of internal state
36+
// since the fast integer types will be at least 32 and 8 bits respectively
3337

34-
std::uint32_t significand_ {};
35-
std::uint8_t exponent_ {};
38+
std::uint_fast32_t significand_ {};
39+
std::uint_fast8_t exponent_ {};
3640
bool sign_ {};
3741

3842
constexpr auto isneg() const noexcept -> bool
3943
{
4044
return sign_;
4145
}
4246

43-
constexpr auto full_significand() const noexcept -> std::uint32_t
47+
constexpr auto full_significand() const noexcept -> std::uint_fast32_t
4448
{
4549
return significand_;
4650
}
4751

48-
constexpr auto unbiased_exponent() const noexcept -> std::uint8_t
52+
constexpr auto unbiased_exponent() const noexcept -> std::uint_fast8_t
4953
{
5054
return exponent_;
5155
}
@@ -57,13 +61,21 @@ class decimal32_fast final
5761

5862
friend constexpr auto div_impl(decimal32_fast lhs, decimal32_fast rhs, decimal32_fast& q, decimal32_fast& r) noexcept -> void;
5963

64+
friend constexpr auto mod_impl(decimal32_fast lhs, decimal32_fast rhs, const decimal32_fast& q, decimal32_fast& r) noexcept -> void;
65+
6066
// Attempts conversion to integral type:
6167
// If this is nan sets errno to EINVAL and returns 0
6268
// If this is not representable sets errno to ERANGE and returns 0
6369
template <typename Decimal, typename TargetType>
6470
friend constexpr auto to_integral(Decimal val) noexcept
6571
BOOST_DECIMAL_REQUIRES_TWO_RETURN(detail::is_decimal_floating_point_v, Decimal, detail::is_integral_v, TargetType, TargetType);
6672

73+
template <BOOST_DECIMAL_DECIMAL_FLOATING_TYPE T>
74+
friend constexpr auto frexp10(T num, int* expptr) noexcept -> typename T::significand_type;
75+
76+
template <BOOST_DECIMAL_DECIMAL_FLOATING_TYPE TargetType, BOOST_DECIMAL_DECIMAL_FLOATING_TYPE Decimal>
77+
friend constexpr auto to_decimal(Decimal val) noexcept -> TargetType;
78+
6779
public:
6880
constexpr decimal32_fast() noexcept : significand_{}, exponent_{}, sign_ {} {}
6981

@@ -105,12 +117,14 @@ class decimal32_fast final
105117
friend constexpr auto operator-(decimal32_fast lhs, decimal32_fast rhs) noexcept -> decimal32_fast;
106118
friend constexpr auto operator*(decimal32_fast lhs, decimal32_fast rhs) noexcept -> decimal32_fast;
107119
friend constexpr auto operator/(decimal32_fast lhs, decimal32_fast rhs) noexcept -> decimal32_fast;
120+
friend constexpr auto operator%(decimal32_fast lhs, decimal32_fast rhs) noexcept -> decimal32_fast;
108121

109122
// Compound operators
110123
constexpr auto operator+=(decimal32_fast rhs) noexcept -> decimal32_fast&;
111124
constexpr auto operator-=(decimal32_fast rhs) noexcept -> decimal32_fast&;
112125
constexpr auto operator*=(decimal32_fast rhs) noexcept -> decimal32_fast&;
113126
constexpr auto operator/=(decimal32_fast rhs) noexcept -> decimal32_fast&;
127+
constexpr auto operator%=(decimal32_fast rhs) noexcept -> decimal32_fast&;
114128

115129
// Increment and decrement
116130
constexpr auto operator++() noexcept -> decimal32_fast&;
@@ -136,31 +150,10 @@ class decimal32_fast final
136150
explicit constexpr operator detail::uint128_t() const noexcept;
137151
#endif
138152

139-
#if !defined(BOOST_DECIMAL_DISABLE_CLIB)
140-
141-
// TODO(mborland): Remove and use the base implementation in io.hpp
142-
template <typename charT, typename traits>
143-
friend auto operator<<(std::basic_ostream<charT, traits>& os, const decimal32_fast& d) -> std::basic_ostream<charT, traits>&
144-
{
145-
if (d.sign_)
146-
{
147-
os << '-';
148-
}
149-
150-
os << d.significand_ << "e";
151-
const auto biased_exp {d.biased_exponent()};
152-
if (biased_exp > 0)
153-
{
154-
os << '+';
155-
}
156-
os << biased_exp;
157-
158-
return os;
159-
}
153+
template <BOOST_DECIMAL_DECIMAL_FLOATING_TYPE Decimal, std::enable_if_t<detail::is_decimal_floating_point_v<Decimal>, bool> = true>
154+
explicit constexpr operator Decimal() const noexcept;
160155

161-
#endif
162-
163-
friend constexpr auto direct_init(std::uint32_t significand, std::uint8_t exponent, bool sign) noexcept -> decimal32_fast;
156+
friend constexpr auto direct_init(std::uint_fast32_t significand, std::uint_fast8_t exponent, bool sign) noexcept -> decimal32_fast;
164157
};
165158

166159
template <typename T1, typename T2, std::enable_if_t<detail::is_integral_v<T1> && detail::is_integral_v<T2>, bool>>
@@ -191,27 +184,26 @@ constexpr decimal32_fast::decimal32_fast(T1 coeff, T2 exp, bool sign) noexcept
191184
# pragma GCC diagnostic pop
192185
#endif
193186

194-
exp += static_cast<std::uint8_t>(digits_to_remove);
187+
exp += static_cast<std::uint_fast8_t>(digits_to_remove);
195188
exp += static_cast<T2>(detail::fenv_round(unsigned_coeff, isneg));
196189
}
197190

198-
auto reduced_coeff {static_cast<std::uint32_t>(unsigned_coeff)};
199-
significand_ = static_cast<std::uint32_t>(reduced_coeff);
191+
significand_ = static_cast<std::uint_fast32_t>(unsigned_coeff);
200192

201193
// Normalize the handling of zeros
202194
if (significand_ == UINT32_C(0))
203195
{
204196
exp = 0;
205197
}
206198

207-
auto biased_exp {static_cast<std::uint32_t>(exp + detail::bias)};
199+
auto biased_exp {static_cast<std::uint_fast32_t>(exp + detail::bias)};
208200
if (biased_exp > std::numeric_limits<std::uint8_t>::max())
209201
{
210202
significand_ = detail::d32_fast_inf;
211203
}
212204
else
213205
{
214-
exponent_ = static_cast<std::uint8_t>(biased_exp);
206+
exponent_ = static_cast<std::uint_fast8_t>(biased_exp);
215207
}
216208
}
217209

@@ -254,7 +246,7 @@ BOOST_DECIMAL_CXX20_CONSTEXPR decimal32_fast::decimal32_fast(Float val) noexcept
254246
# pragma GCC diagnostic pop
255247
#endif
256248

257-
constexpr auto direct_init(std::uint32_t significand, std::uint8_t exponent, bool sign = false) noexcept -> decimal32_fast
249+
constexpr auto direct_init(std::uint_fast32_t significand, std::uint_fast8_t exponent, bool sign = false) noexcept -> decimal32_fast
258250
{
259251
decimal32_fast val;
260252
val.significand_ = significand;
@@ -526,15 +518,24 @@ constexpr auto div_impl(decimal32_fast lhs, decimal32_fast rhs, decimal32_fast&
526518
<< "\nexp rhs: " << exp_rhs << std::endl;
527519
#endif
528520

529-
detail::decimal32_components lhs_components {sig_lhs, exp_lhs, lhs.isneg()};
530-
detail::decimal32_components rhs_components {sig_rhs, exp_rhs, rhs.isneg()};
521+
detail::decimal32_components lhs_components {static_cast<std::uint32_t>(sig_lhs), exp_lhs, lhs.isneg()};
522+
detail::decimal32_components rhs_components {static_cast<std::uint32_t>(sig_rhs), exp_rhs, rhs.isneg()};
531523
detail::decimal32_components q_components {};
532524

533525
generic_div_impl(lhs_components, rhs_components, q_components);
534526

535527
q = decimal32_fast(q_components.sig, q_components.exp, q_components.sign);
536528
}
537529

530+
constexpr auto mod_impl(decimal32_fast lhs, decimal32_fast rhs, const decimal32_fast& q, decimal32_fast& r) noexcept -> void
531+
{
532+
constexpr decimal32_fast zero {0, 0};
533+
534+
// https://en.cppreference.com/w/cpp/numeric/math/fmod
535+
auto q_trunc {q > zero ? floor(q) : ceil(q)};
536+
r = lhs - (decimal32_fast(q_trunc) * rhs);
537+
}
538+
538539
constexpr auto operator/(decimal32_fast lhs, decimal32_fast rhs) noexcept -> decimal32_fast
539540
{
540541
decimal32_fast q {};
@@ -544,6 +545,22 @@ constexpr auto operator/(decimal32_fast lhs, decimal32_fast rhs) noexcept -> dec
544545
return q;
545546
}
546547

548+
constexpr auto operator%(decimal32_fast lhs, decimal32_fast rhs) noexcept -> decimal32_fast
549+
{
550+
decimal32_fast q {};
551+
decimal32_fast r {};
552+
div_impl(lhs, rhs, q, r);
553+
mod_impl(lhs, rhs, q, r);
554+
555+
return r;
556+
}
557+
558+
constexpr auto decimal32_fast::operator%=(decimal32_fast rhs) noexcept -> decimal32_fast&
559+
{
560+
*this = *this % rhs;
561+
return *this;
562+
}
563+
547564
constexpr auto decimal32_fast::operator+=(decimal32_fast rhs) noexcept -> decimal32_fast&
548565
{
549566
*this = *this + rhs;
@@ -662,6 +679,12 @@ constexpr decimal32_fast::operator detail::uint128_t() const noexcept
662679

663680
#endif
664681

682+
template <BOOST_DECIMAL_DECIMAL_FLOATING_TYPE Decimal, std::enable_if_t<detail::is_decimal_floating_point_v<Decimal>, bool>>
683+
constexpr decimal32_fast::operator Decimal() const noexcept
684+
{
685+
return to_decimal<Decimal>(*this);
686+
}
687+
665688
} // namespace decimal
666689
} // namespace boost
667690

@@ -705,7 +728,7 @@ struct numeric_limits<boost::decimal::decimal32_fast>
705728
BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr int min_exponent10 = min_exponent;
706729
BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr int max_exponent = 96;
707730
BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr int max_exponent10 = max_exponent;
708-
BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool traps = numeric_limits<std::uint32_t>::traps;
731+
BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool traps = numeric_limits<std::uint_fast32_t>::traps;
709732
BOOST_DECIMAL_ATTRIBUTE_UNUSED static constexpr bool tinyness_before = true;
710733

711734
// Member functions

include/boost/decimal/decimal64.hpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,9 @@ struct decimal64_components
132132

133133
BOOST_DECIMAL_EXPORT class decimal64 final
134134
{
135+
public:
136+
using significand_type = std::uint64_t;
137+
135138
private:
136139

137140
std::uint64_t bits_ {};
@@ -563,10 +566,7 @@ BOOST_DECIMAL_EXPORT class decimal64 final
563566

564567
// <cmath> functions that need to be friends
565568
template <BOOST_DECIMAL_DECIMAL_FLOATING_TYPE T>
566-
friend constexpr auto frexp10(T num, int* expptr) noexcept
567-
-> std::enable_if_t<detail::is_decimal_floating_point_v<T>,
568-
std::conditional_t<std::is_same<T, decimal32>::value, std::uint32_t,
569-
std::conditional_t<std::is_same<T, decimal64>::value, std::uint64_t, detail::uint128>>>;
569+
friend constexpr auto frexp10(T num, int* expptr) noexcept -> typename T::significand_type;
570570

571571
friend constexpr auto copysignd64(decimal64 mag, decimal64 sgn) noexcept -> decimal64;
572572
friend constexpr auto fmad64(decimal64 x, decimal64 y, decimal64 z) noexcept -> decimal64;

include/boost/decimal/detail/cmath/ceil.hpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,7 @@ BOOST_DECIMAL_EXPORT template <typename T>
2727
constexpr auto ceil BOOST_DECIMAL_PREVENT_MACRO_SUBSTITUTION (T val) noexcept
2828
BOOST_DECIMAL_REQUIRES(detail::is_decimal_floating_point_v, T)
2929
{
30-
using DivType = std::conditional_t<std::is_same<T, decimal32>::value, std::uint32_t,
31-
std::conditional_t<std::is_same<T, decimal64>::value, std::uint64_t, detail::uint128>>;
30+
using DivType = typename T::significand_type;
3231

3332
constexpr T zero {0, 0};
3433
constexpr T one {1, 0};

include/boost/decimal/detail/cmath/floor.hpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,7 @@ BOOST_DECIMAL_EXPORT template <typename T>
2727
constexpr auto floor BOOST_DECIMAL_PREVENT_MACRO_SUBSTITUTION (T val) noexcept
2828
BOOST_DECIMAL_REQUIRES(detail::is_decimal_floating_point_v, T)
2929
{
30-
using DivType = std::conditional_t<std::is_same<T, decimal32>::value, std::uint32_t,
31-
std::conditional_t<std::is_same<T, decimal64>::value, std::uint64_t, detail::uint128>>;
30+
using DivType = typename T::significand_type;
3231

3332
constexpr T zero {0, 0};
3433
constexpr T neg_one {1, 0, true};

0 commit comments

Comments
 (0)