@@ -19,33 +19,37 @@ namespace decimal {
1919
2020namespace 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
2828class decimal32_fast final
2929{
30+ public:
31+ using significand_type = std::uint_fast32_t ;
32+
3033private:
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+
6779public:
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
166159template <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 << " \n exp 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+
538539constexpr 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+
547564constexpr 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
0 commit comments