Skip to content

Commit

Permalink
Merge pull request #703 from cppalliance/comp
Browse files Browse the repository at this point in the history
Improve comparison operators for decimal32 and decimal32_fast
  • Loading branch information
mborland authored Jul 10, 2024
2 parents 1ff2bbd + ae22722 commit c115908
Show file tree
Hide file tree
Showing 3 changed files with 114 additions and 40 deletions.
29 changes: 9 additions & 20 deletions include/boost/decimal/decimal32.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -1101,27 +1101,16 @@ constexpr auto operator!=(Integer lhs, decimal32 rhs) noexcept
constexpr auto operator<(decimal32 lhs, decimal32 rhs) noexcept -> bool
{
#ifndef BOOST_DECIMAL_FAST_MATH
if (isnan(lhs) || isnan(rhs) ||
(!lhs.isneg() && rhs.isneg()))
{
return false;
}
else if (lhs.isneg() && !rhs.isneg())
{
return true;
}
else if (isfinite(lhs) && isinf(rhs))
{
return !rhs.isneg();
}
#else
if (!lhs.isneg() && rhs.isneg())
{
return false;
}
else if (lhs.isneg() && !rhs.isneg())
if (!isfinite(lhs) || !isfinite(rhs))
{
return true;
if (isnan(lhs) || isnan(rhs))
{
return false;
}
else if (isfinite(lhs) && isinf(rhs))
{
return !rhs.isneg();
}
}
#endif

Expand Down
39 changes: 21 additions & 18 deletions include/boost/decimal/decimal32_fast.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -486,9 +486,9 @@ constexpr auto operator==(decimal32_fast lhs, decimal32_fast rhs) noexcept -> bo
}
#endif

return lhs.sign_ == rhs.sign_ &&
lhs.exponent_ == rhs.exponent_ &&
lhs.significand_ == rhs.significand_;
return (lhs.sign_ == rhs.sign_) &
(lhs.exponent_ == rhs.exponent_) &
(lhs.significand_ == rhs.significand_);
}

constexpr auto operator!=(decimal32_fast lhs, decimal32_fast rhs) noexcept -> bool
Expand All @@ -499,22 +499,25 @@ constexpr auto operator!=(decimal32_fast lhs, decimal32_fast rhs) noexcept -> bo
constexpr auto operator<(decimal32_fast lhs, decimal32_fast rhs) noexcept -> bool
{
#ifndef BOOST_DECIMAL_FAST_MATH
if (isnan(lhs) || isnan(rhs) ||
(!lhs.isneg() && rhs.isneg()))
{
return false;
}
else if (lhs.isneg() && !rhs.isneg())
{
return true;
}
else if (isfinite(lhs) && isinf(rhs))
{
return !signbit(rhs);
}
else if (isinf(lhs) && isfinite(rhs))
if (!isfinite(lhs) || !isfinite(rhs))
{
return signbit(rhs);
if (isnan(lhs) || isnan(rhs) ||
(!lhs.isneg() && rhs.isneg()))
{
return false;
}
else if (lhs.isneg() && !rhs.isneg())
{
return true;
}
else if (isfinite(lhs) && isinf(rhs))
{
return !signbit(rhs);
}
else if (isinf(lhs) && isfinite(rhs))
{
return signbit(rhs);
}
}
#else
if (!lhs.isneg() && rhs.isneg())
Expand Down
86 changes: 84 additions & 2 deletions include/boost/decimal/detail/comparison.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include <boost/decimal/detail/shrink_significand.hpp>
#include <boost/decimal/detail/cmath/isfinite.hpp>
#include <boost/decimal/detail/concepts.hpp>
#include <boost/decimal/detail/power_tables.hpp>

#ifndef BOOST_DECIMAL_BUILD_MODULE
#include <limits>
Expand All @@ -26,7 +27,54 @@ namespace decimal {
template <BOOST_DECIMAL_DECIMAL_FLOATING_TYPE DecimalType = decimal32, BOOST_DECIMAL_INTEGRAL T1,
BOOST_DECIMAL_INTEGRAL U1, BOOST_DECIMAL_INTEGRAL T2, BOOST_DECIMAL_INTEGRAL U2>
constexpr auto equal_parts_impl(T1 lhs_sig, U1 lhs_exp, bool lhs_sign,
T2 rhs_sig, U2 rhs_exp, bool rhs_sign) noexcept -> bool
T2 rhs_sig, U2 rhs_exp, bool rhs_sign) noexcept -> std::enable_if_t<std::is_same<DecimalType, decimal32>::value, bool>
{
using comp_type = std::uint_fast64_t;

BOOST_DECIMAL_ASSERT(lhs_sig >= 0);
BOOST_DECIMAL_ASSERT(rhs_sig >= 0);

// We con compare signs right away
if (lhs_sign != rhs_sign)
{
return false;
}

auto new_lhs_sig {static_cast<comp_type>(lhs_sig)};
auto new_rhs_sig {static_cast<comp_type>(rhs_sig)};

const auto delta_exp {lhs_exp - rhs_exp};

// Check the value of delta exp to avoid to large a value for pow10
if (delta_exp > detail::precision_v<DecimalType> || delta_exp < -detail::precision_v<DecimalType>)
{
return false;
}

if (delta_exp >= 0)
{
new_lhs_sig *= detail::pow10(static_cast<comp_type>(delta_exp));
}
else
{
new_rhs_sig *= detail::pow10(static_cast<comp_type>(-delta_exp));
}

#ifdef BOOST_DECIMAL_DEBUG_EQUAL
std::cerr << "Normalized Values"
<< "\nlhs_sig: " << new_lhs_sig
<< "\nlhs_exp: " << lhs_exp
<< "\nrhs_sig: " << new_rhs_sig
<< "\nrhs_exp: " << rhs_exp << std::endl;
#endif

return new_lhs_sig == new_rhs_sig;
}

template <BOOST_DECIMAL_DECIMAL_FLOATING_TYPE DecimalType = decimal32, BOOST_DECIMAL_INTEGRAL T1,
BOOST_DECIMAL_INTEGRAL U1, BOOST_DECIMAL_INTEGRAL T2, BOOST_DECIMAL_INTEGRAL U2>
constexpr auto equal_parts_impl(T1 lhs_sig, U1 lhs_exp, bool lhs_sign,
T2 rhs_sig, U2 rhs_exp, bool rhs_sign) noexcept -> std::enable_if_t<!std::is_same<DecimalType, decimal32>::value, bool>
{
using comp_type = std::conditional_t<(std::numeric_limits<T1>::digits10 > std::numeric_limits<T2>::digits10), T1, T2>;

Expand Down Expand Up @@ -113,10 +161,44 @@ constexpr auto operator!=(Decimal1 lhs, Decimal2 rhs) noexcept
return !(mixed_decimal_equality_impl(lhs, rhs));
}

template <BOOST_DECIMAL_DECIMAL_FLOATING_TYPE DecimalType = decimal32, BOOST_DECIMAL_INTEGRAL T1,
BOOST_DECIMAL_INTEGRAL U1, BOOST_DECIMAL_INTEGRAL T2, BOOST_DECIMAL_INTEGRAL U2>
constexpr auto less_parts_impl(T1 lhs_sig, U1 lhs_exp, bool lhs_sign,
T2 rhs_sig, U2 rhs_exp, bool rhs_sign) noexcept -> std::enable_if_t<std::is_same<DecimalType, decimal32>::value, bool>
{
using comp_type = std::uint_fast64_t;

BOOST_DECIMAL_ASSERT(lhs_sig >= 0);
BOOST_DECIMAL_ASSERT(rhs_sig >= 0);

if (lhs_sign != rhs_sign)
{
return lhs_sign;
}

auto new_lhs_sig {static_cast<comp_type>(lhs_sig)};
auto new_rhs_sig {static_cast<comp_type>(rhs_sig)};

if (new_lhs_sig == UINT64_C(0) || new_rhs_sig == UINT64_C(0))
{
return (new_lhs_sig == new_rhs_sig) ? false : (new_lhs_sig == 0 ? !rhs_sign : lhs_sign);
}

detail::normalize<DecimalType>(new_lhs_sig, lhs_exp);
detail::normalize<DecimalType>(new_rhs_sig, rhs_exp);

if (lhs_exp != rhs_exp)
{
return lhs_sign ? lhs_exp > rhs_exp : lhs_exp < rhs_exp;
}

return lhs_sign ? new_lhs_sig > new_rhs_sig : new_lhs_sig < new_rhs_sig;
}

template <BOOST_DECIMAL_DECIMAL_FLOATING_TYPE DecimalType = decimal32, BOOST_DECIMAL_INTEGRAL T1,
BOOST_DECIMAL_INTEGRAL U1, BOOST_DECIMAL_INTEGRAL T2, BOOST_DECIMAL_INTEGRAL U2>
constexpr auto less_parts_impl(T1 lhs_sig, U1 lhs_exp, bool lhs_sign,
T2 rhs_sig, U2 rhs_exp, bool rhs_sign) noexcept -> bool
T2 rhs_sig, U2 rhs_exp, bool rhs_sign) noexcept -> std::enable_if_t<!std::is_same<DecimalType, decimal32>::value, bool>
{
using comp_type = std::conditional_t<(std::numeric_limits<T1>::digits10 > std::numeric_limits<T2>::digits10), T1, T2>;

Expand Down

0 comments on commit c115908

Please sign in to comment.