@@ -34,8 +34,7 @@ constexpr auto nextafter_impl(const DecimalType val, const bool direction) noexc
3434{
3535 constexpr DecimalType zero {0 };
3636
37- // Val < direction = +
38- // Val > direction = -
37+ const bool is_neg {val < 0 };
3938 const auto abs_val {abs (val)};
4039
4140 if (val == zero)
@@ -44,32 +43,48 @@ constexpr auto nextafter_impl(const DecimalType val, const bool direction) noexc
4443 -std::numeric_limits<DecimalType>::denorm_min ()};
4544 return min_val;
4645 }
47- else if (abs_val > zero && abs_val < std::numeric_limits<DecimalType>::epsilon ())
48- {
49- auto exp {val.biased_exponent ()};
50- auto significand {val.full_significand ()};
51- direction ? ++significand : --significand;
5246
53- return {significand, exp, val.isneg ()};
54- }
47+ const auto components {val.to_components ()};
48+ auto sig {components.sig };
49+ auto exp {components.exp };
50+ const auto removed_zeros {remove_trailing_zeros (sig)};
51+ const auto sig_dig {num_digits (sig)};
5552
56- const auto val_eps {direction ? val + std::numeric_limits<DecimalType>::epsilon () :
57- val - std::numeric_limits<DecimalType>::epsilon ()};
53+ // Our two boundaries
54+ const bool is_pow_10 {removed_zeros.trimmed_number == 1U };
55+ const bool is_max_sig {sig == detail::max_significand_v<DecimalType>};
5856
59- // If adding epsilon does nothing, then we need to manipulate the representation
60- if (val == val_eps)
57+ if (sig_dig < detail::precision_v<DecimalType>)
6158 {
62- int exp {} ;
63- auto significand { frexp10 (val, &exp)} ;
64-
65- direction ? ++significand : --significand;
59+ const auto offset{detail::precision_v<DecimalType> - sig_dig} ;
60+ sig *= pow10 ( static_cast < decltype (sig)>(detail::precision_v<DecimalType> - sig_dig)) ;
61+ exp -= offset;
62+ }
6663
67- return DecimalType{significand, exp};
64+ if (direction)
65+ {
66+ // Val < direction = +
67+ ++sig;
68+ if (is_max_sig)
69+ {
70+ sig /= 10u ;
71+ ++exp;
72+ }
6873 }
6974 else
7075 {
71- return val_eps;
76+ // Val > direction = -
77+ --sig;
78+ if (is_pow_10)
79+ {
80+ // 1000 becomes 999 but needs to be 9999
81+ sig *= 10u ;
82+ sig += 9u ;
83+ --exp;
84+ }
7285 }
86+
87+ return DecimalType{sig, exp, is_neg};
7388}
7489
7590} // namespace detail
0 commit comments