2626namespace boost {
2727namespace decimal {
2828
29+ #ifdef _MSC_VER
30+ #pragma warning(push)
31+ #pragma warning(disable:4127)
32+ #endif
33+
2934template <BOOST_DECIMAL_DECIMAL_FLOATING_TYPE DecimalType>
3035BOOST_DECIMAL_FORCE_INLINE constexpr auto equality_impl (DecimalType lhs, DecimalType rhs) noexcept -> bool
3136{
@@ -75,75 +80,109 @@ BOOST_DECIMAL_FORCE_INLINE constexpr auto equality_impl(DecimalType lhs, Decimal
7580 }
7681
7782 // Step 6: Normalize the significand and compare
78- // Instead of multiplying the larger number, divide the smaller one
79- if (delta_exp >= 0 )
83+ BOOST_DECIMAL_IF_CONSTEXPR (detail::decimal_val_v<DecimalType> >= 128 )
8084 {
81- // Check if we can divide rhs_sig safely
82- if (delta_exp > 0 && rhs_sig % detail::pow10 (static_cast <comp_type>(delta_exp)) != 0U )
85+ // Instead of multiplying the larger number, divide the smaller one
86+ //
87+ // We try for multiplication even though it's a small range
88+ // Since it's an order of magnitude faster
89+ if (delta_exp <= 4 && delta_exp >= 4 )
8390 {
84- return false ;
91+ if (delta_exp > 0 )
92+ {
93+ lhs_sig *= detail::pow10 (static_cast <comp_type>(delta_exp));
94+ }
95+ else if (delta_exp < 0 )
96+ {
97+ rhs_sig *= detail::pow10 (static_cast <comp_type>(-delta_exp));
98+ }
8599 }
86- rhs_sig /= detail::pow10 (static_cast <comp_type>(delta_exp));
100+ else if (delta_exp > 0 )
101+ {
102+ // Check if we can divide rhs_sig safely
103+ // E.g. 9e0 != 90000000204928e-13 but if we just did division we would falsely get 9 ?= 9
104+ if (rhs_sig % detail::pow10 (static_cast <comp_type>(delta_exp)) != 0U )
105+ {
106+ return false ;
107+ }
108+ rhs_sig /= detail::pow10 (static_cast <comp_type>(delta_exp));
109+ }
110+ else if (delta_exp < 0 )
111+ {
112+ // Check if we can divide lhs_sig safely
113+ if (lhs_sig % detail::pow10 (static_cast <comp_type>(-delta_exp)) != 0U )
114+ {
115+ return false ;
116+ }
117+ lhs_sig /= detail::pow10 (static_cast <comp_type>(-delta_exp));
118+ }
119+
120+ return lhs_sig == rhs_sig;
87121 }
88122 else
89123 {
90- // Check if we can divide lhs_sig safely
91- if (lhs_sig % detail::pow10 (static_cast <comp_type>(-delta_exp)) != 0U )
124+ using promoted_sig_type = std::conditional_t <std::is_same<typename DecimalType::significand_type, std::uint32_t >::value, std::uint64_t , int128::uint128_t >;
125+ promoted_sig_type promotes_lhs {lhs_sig};
126+ promoted_sig_type promotes_rhs {rhs_sig};
127+
128+ if (delta_exp > 0 )
92129 {
93- return false ;
130+ promotes_lhs *= detail::pow10 (static_cast <promoted_sig_type>(delta_exp));
131+ }
132+ else if (delta_exp < 0 )
133+ {
134+ promotes_rhs *= detail::pow10 (static_cast <promoted_sig_type>(-delta_exp));
94135 }
95- lhs_sig /= detail::pow10 (static_cast <comp_type>(-delta_exp));
96- }
97136
98- return lhs_sig == rhs_sig;
137+ return promotes_lhs == promotes_rhs;
138+ }
99139}
100140
141+ #ifdef _MSC_VER
142+ #pragma warning(pop)
143+ #endif
144+
101145template <BOOST_DECIMAL_FAST_DECIMAL_FLOATING_TYPE DecimalType>
102146BOOST_DECIMAL_FORCE_INLINE constexpr auto fast_equality_impl (const DecimalType& lhs, const DecimalType& rhs) noexcept -> bool
103147{
104- if (lhs.significand_ == 0U && rhs.significand_ == 0U )
105- {
106- // -0 == +0
107- return true ;
108- }
109-
110- if (lhs.exponent_ != rhs.exponent_ )
111- {
112- return false ;
113- }
114- if (lhs.significand_ != rhs.significand_ )
148+ #ifndef BOOST_DECIMAL_FAST_MATH
149+ if (isnan (lhs) || isnan (rhs))
115150 {
116151 return false ;
117152 }
153+ #endif
118154
119- #ifndef BOOST_DECIMAL_FAST_MATH
120- if (isnan (lhs))
155+ const auto lhs_sig {lhs.significand_ };
156+ const auto rhs_sig {rhs.significand_ };
157+
158+ if (lhs_sig == 0U && rhs_sig == 0U )
121159 {
122- return false ;
160+ // -0 == +0
161+ return true ;
123162 }
124- #endif
125163
126- return lhs.sign_ == rhs.sign_ ;
164+ return lhs_sig == rhs_sig &&
165+ lhs.exponent_ == rhs.exponent_ &&
166+ lhs.sign_ == rhs.sign_ ;
127167}
128168
129169template <BOOST_DECIMAL_FAST_DECIMAL_FLOATING_TYPE DecimalType>
130170BOOST_DECIMAL_FORCE_INLINE constexpr auto fast_inequality_impl (const DecimalType& lhs, const DecimalType& rhs) noexcept -> bool
131171{
132- return
133- #ifndef BOOST_DECIMAL_FAST_MATH
134- isnan (lhs) || isnan (rhs) ||
135- #endif
136- (lhs.sign_ != rhs.sign_ ) ||
137- (lhs.exponent_ != rhs.exponent_ ) ||
138- (lhs.significand_ != rhs.significand_ );
172+ return !fast_equality_impl (lhs, rhs);
139173}
140174
175+ #ifdef _MSC_VER
176+ #pragma warning(push)
177+ #pragma warning(disable:4127) // BOOST_DECIMAL_IF_CONSTEXPR prior to C++17 is constant conditional expression
178+ #endif
179+
141180template <BOOST_DECIMAL_DECIMAL_FLOATING_TYPE DecimalType = decimal32, BOOST_DECIMAL_INTEGRAL T1,
142181 BOOST_DECIMAL_INTEGRAL U1, BOOST_DECIMAL_INTEGRAL T2, BOOST_DECIMAL_INTEGRAL U2>
143182constexpr auto equal_parts_impl (T1 lhs_sig, U1 lhs_exp, bool lhs_sign,
144183 T2 rhs_sig, U2 rhs_exp, bool rhs_sign) noexcept -> std::enable_if_t<detail::is_ieee_type_v<DecimalType>, bool>
145184{
146- using comp_type = std::conditional_t <(std::numeric_limits<T1>::digits10 > std::numeric_limits<T2>::digits10), T1, T2>;
185+ using comp_type = detail:: make_unsigned_t < std::conditional_t <(std::numeric_limits<T1>::digits10 > std::numeric_limits<T2>::digits10), T1, T2> >;
147186
148187 BOOST_DECIMAL_ASSERT (lhs_sig >= 0U );
149188 BOOST_DECIMAL_ASSERT (rhs_sig >= 0U );
@@ -154,14 +193,11 @@ constexpr auto equal_parts_impl(T1 lhs_sig, U1 lhs_exp, bool lhs_sign,
154193 return false ;
155194 }
156195
157- auto new_lhs_sig {static_cast <comp_type>(lhs_sig)};
158- auto new_rhs_sig {static_cast <comp_type>(rhs_sig)};
159-
160196 const auto delta_exp {lhs_exp - rhs_exp};
161197
162198 // Check the value of delta exp to avoid to large a value for pow10
163199 // Also if only one of the significands is 0 then we know the values have to be mismatched
164- if (new_lhs_sig == static_cast <comp_type>( 0 ) && new_rhs_sig == static_cast <comp_type>( 0 ) )
200+ if (lhs_sig == 0U && rhs_sig == 0U )
165201 {
166202 return true ;
167203 }
@@ -170,38 +206,73 @@ constexpr auto equal_parts_impl(T1 lhs_sig, U1 lhs_exp, bool lhs_sign,
170206 return false ;
171207 }
172208
209+ auto new_lhs_sig {static_cast <comp_type>(lhs_sig)};
210+ auto new_rhs_sig {static_cast <comp_type>(rhs_sig)};
211+
173212 // Step 5: Normalize the significand and compare
174213 // Instead of multiplying the larger number, divide the smaller one
175- if (delta_exp >= 0 )
214+ BOOST_DECIMAL_IF_CONSTEXPR (detail::decimal_val_v<DecimalType> >= 128 )
176215 {
177- // Check if we can divide rhs_sig safely
178- if (delta_exp > 0 && new_rhs_sig % detail::pow10 (static_cast <comp_type>(delta_exp)) != 0U )
216+ // Instead of multiplying the larger number, divide the smaller one
217+ //
218+ // We try for multiplication even though it's a small range
219+ // Since it's an order of magnitude faster
220+ if (delta_exp <= 4 && delta_exp >= 4 )
179221 {
180- return false ;
222+ if (delta_exp > 0 )
223+ {
224+ new_lhs_sig *= detail::pow10 (static_cast <comp_type>(delta_exp));
225+ }
226+ else if (delta_exp < 0 )
227+ {
228+ new_rhs_sig *= detail::pow10 (static_cast <comp_type>(-delta_exp));
229+ }
230+ }
231+ else if (delta_exp > 0 )
232+ {
233+ // Check if we can divide rhs_sig safely
234+ // E.g. 9e0 != 90000000204928e-13 but if we just did division we would falsely get 9 ?= 9
235+ if (new_rhs_sig % detail::pow10 (static_cast <comp_type>(delta_exp)) != 0U )
236+ {
237+ return false ;
238+ }
239+ new_rhs_sig /= detail::pow10 (static_cast <comp_type>(delta_exp));
181240 }
182- new_rhs_sig /= detail::pow10 (static_cast <comp_type>(delta_exp));
241+ else if (delta_exp < 0 )
242+ {
243+ // Check if we can divide lhs_sig safely
244+ if (new_lhs_sig % detail::pow10 (static_cast <comp_type>(-delta_exp)) != 0U )
245+ {
246+ return false ;
247+ }
248+ new_lhs_sig /= detail::pow10 (static_cast <comp_type>(-delta_exp));
249+ }
250+
251+ return new_lhs_sig == new_rhs_sig;
183252 }
184253 else
185254 {
186- // Check if we can divide lhs_sig safely
187- if (new_lhs_sig % detail::pow10 (static_cast <comp_type>(-delta_exp)) != 0U )
255+ using promoted_sig_type = std::conditional_t <std::is_same<comp_type, std::uint32_t >::value, std::uint64_t , int128::uint128_t >;
256+ promoted_sig_type promotes_lhs {new_lhs_sig};
257+ promoted_sig_type promotes_rhs {new_rhs_sig};
258+
259+ if (delta_exp > 0 )
188260 {
189- return false ;
261+ promotes_lhs *= detail::pow10 (static_cast <promoted_sig_type>(delta_exp));
262+ }
263+ else if (delta_exp < 0 )
264+ {
265+ promotes_rhs *= detail::pow10 (static_cast <promoted_sig_type>(-delta_exp));
190266 }
191- new_lhs_sig /= detail::pow10 (static_cast <comp_type>(-delta_exp));
192- }
193-
194- #ifdef BOOST_DECIMAL_DEBUG_EQUAL
195- std::cerr << " Normalized Values"
196- << " \n lhs_sig: " << new_lhs_sig
197- << " \n lhs_exp: " << lhs_exp
198- << " \n rhs_sig: " << new_rhs_sig
199- << " \n rhs_exp: " << rhs_exp << std::endl;
200- #endif
201267
202- return new_lhs_sig == new_rhs_sig;
268+ return promotes_lhs == promotes_rhs;
269+ }
203270}
204271
272+ #ifdef _MSC_VER
273+ #pragma warning(pop)
274+ #endif
275+
205276template <BOOST_DECIMAL_DECIMAL_FLOATING_TYPE DecimalType = decimal32, BOOST_DECIMAL_INTEGRAL T1,
206277 BOOST_DECIMAL_INTEGRAL U1, BOOST_DECIMAL_INTEGRAL T2, BOOST_DECIMAL_INTEGRAL U2>
207278constexpr auto equal_parts_impl (T1 lhs_sig, U1 lhs_exp, bool lhs_sign,
0 commit comments