Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Dd00000000001000000000000000000000000000000000001000000000cccccccccÿCccc0ccccccccc8888000010000)001.2
1 change: 1 addition & 0 deletions fuzzing/old_crashes/fuzz_snprintf/crash-github-1
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
0000000000000000000000000000000000000000
8 changes: 4 additions & 4 deletions include/boost/decimal/charconv.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -353,7 +353,7 @@ BOOST_DECIMAL_CONSTEXPR auto to_chars_scientific_impl(char* first, char* last, c
}

const auto fp = fpclassify(value);
if (fp != FP_NORMAL)
if (!(fp == FP_NORMAL || fp == FP_SUBNORMAL))
{
return to_chars_nonfinite(first, last, value, fp, fmt, precision);
}
Expand Down Expand Up @@ -494,7 +494,7 @@ BOOST_DECIMAL_CONSTEXPR auto to_chars_fixed_impl(char* first, char* last, const
}

const auto fp = fpclassify(value);
if (fp != FP_NORMAL)
if (!(fp == FP_NORMAL || fp == FP_SUBNORMAL))
{
return to_chars_nonfinite(first, last, value, fp, fmt, precision);
}
Expand Down Expand Up @@ -720,7 +720,7 @@ BOOST_DECIMAL_CONSTEXPR auto to_chars_hex_impl(char* first, char* last, const Ta
}

const auto fp = fpclassify(value);
if (fp != FP_NORMAL)
if (!(fp == FP_NORMAL || fp == FP_SUBNORMAL))
{
return to_chars_nonfinite(first, last, value, fp, chars_format::hex, precision);
}
Expand All @@ -742,7 +742,7 @@ BOOST_DECIMAL_CONSTEXPR auto to_chars_hex_impl(char* first, char* last, const Ta
Unsigned_Integer significand = frexp10(value, &exp);
BOOST_DECIMAL_ASSERT(significand != 0);
// Strip zeros of the significand since frexp10 normalizes it
while (significand % 10U == 0)
while (significand % 10U == 0 && significand > 0)
{
significand /= 10U;
++exp;
Expand Down
10 changes: 5 additions & 5 deletions include/boost/decimal/decimal128.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2238,18 +2238,18 @@ struct numeric_limits<boost::decimal::decimal128>
static constexpr int digits10 = digits;
static constexpr int max_digits10 = digits;
static constexpr int radix = 10;
static constexpr int min_exponent = -6142;
static constexpr int min_exponent = -6143;
static constexpr int min_exponent10 = min_exponent;
static constexpr int max_exponent = 6145;
static constexpr int max_exponent = 6144;
static constexpr int max_exponent10 = max_exponent;
static constexpr bool traps = numeric_limits<std::uint64_t>::traps;
static constexpr bool tinyness_before = true;

// Member functions
static constexpr auto (min) () -> boost::decimal::decimal128 { return {1, min_exponent}; }
static constexpr auto (max) () -> boost::decimal::decimal128 { return {boost::decimal::detail::uint128{UINT64_C(999'999'999'999'999), UINT64_C(9'999'999'999'999'999'999)}, max_exponent}; }
static constexpr auto lowest () -> boost::decimal::decimal128 { return {boost::decimal::detail::uint128{UINT64_C(999'999'999'999'999), UINT64_C(9'999'999'999'999'999'999)}, max_exponent, true}; }
static constexpr auto epsilon () -> boost::decimal::decimal128 { return {1, -34}; }
static constexpr auto (max) () -> boost::decimal::decimal128 { return {boost::decimal::detail::uint128{UINT64_C(0b1111011010000100110111110101011011000011111000000), UINT64_C(0b0011011110001101100011100110001111111111111111111111111111111111)}, max_exponent - digits + 1}; }
static constexpr auto lowest () -> boost::decimal::decimal128 { return {boost::decimal::detail::uint128{UINT64_C(0b1111011010000100110111110101011011000011111000000), UINT64_C(0b0011011110001101100011100110001111111111111111111111111111111111)}, max_exponent - digits + 1, true}; }
static constexpr auto epsilon () -> boost::decimal::decimal128 { return {1, -digits + 1}; }
static constexpr auto round_error () -> boost::decimal::decimal128 { return epsilon(); }
static constexpr auto infinity () -> boost::decimal::decimal128 { return boost::decimal::from_bits(boost::decimal::detail::d128_inf_mask); }
static constexpr auto quiet_NaN () -> boost::decimal::decimal128 { return boost::decimal::from_bits(boost::decimal::detail::d128_nan_mask); }
Expand Down
14 changes: 7 additions & 7 deletions include/boost/decimal/decimal128_fast.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -1484,25 +1484,25 @@ struct numeric_limits<boost::decimal::decimal128_fast>
static constexpr int digits10 = digits;
static constexpr int max_digits10 = digits;
static constexpr int radix = 10;
static constexpr int min_exponent = -6142;
static constexpr int min_exponent = -6143;
static constexpr int min_exponent10 = min_exponent;
static constexpr int max_exponent = 6145;
static constexpr int max_exponent = 6144;
static constexpr int max_exponent10 = max_exponent;
static constexpr bool traps = numeric_limits<std::uint64_t>::traps;
static constexpr bool tinyness_before = true;

// Member functions
static constexpr auto (min) () -> boost::decimal::decimal128_fast { return {1, min_exponent}; }
static constexpr auto (max) () -> boost::decimal::decimal128_fast { return {boost::decimal::detail::uint128{UINT64_C(999'999'999'999'999), UINT64_C(9'999'999'999'999'999'999)}, max_exponent}; }
static constexpr auto lowest () -> boost::decimal::decimal128_fast { return {boost::decimal::detail::uint128{UINT64_C(999'999'999'999'999), UINT64_C(9'999'999'999'999'999'999)}, max_exponent, true}; }
static constexpr auto epsilon () -> boost::decimal::decimal128_fast { return {1, -34}; }
static constexpr auto (max) () -> boost::decimal::decimal128_fast { return {boost::decimal::detail::uint128{UINT64_C(0b1111011010000100110111110101011011000011111000000), UINT64_C(0b0011011110001101100011100110001111111111111111111111111111111111)}, max_exponent - digits + 1}; }
static constexpr auto lowest () -> boost::decimal::decimal128_fast { return {boost::decimal::detail::uint128{UINT64_C(0b1111011010000100110111110101011011000011111000000), UINT64_C(0b0011011110001101100011100110001111111111111111111111111111111111)}, max_exponent - digits + 1, true}; }
static constexpr auto epsilon () -> boost::decimal::decimal128_fast { return {1, -digits + 1}; }
static constexpr auto round_error () -> boost::decimal::decimal128_fast { return epsilon(); }
static constexpr auto infinity () -> boost::decimal::decimal128_fast { return boost::decimal::direct_init_d128(boost::decimal::detail::d128_fast_inf, 0, false); }
static constexpr auto quiet_NaN () -> boost::decimal::decimal128_fast { return boost::decimal::direct_init_d128(boost::decimal::detail::d128_fast_qnan, 0, false); }
static constexpr auto signaling_NaN() -> boost::decimal::decimal128_fast { return boost::decimal::direct_init_d128(boost::decimal::detail::d128_fast_snan, 0, false); }
static constexpr auto denorm_min () -> boost::decimal::decimal128_fast { return {1, boost::decimal::detail::etiny_v<boost::decimal::decimal128>}; }
static constexpr auto denorm_min () -> boost::decimal::decimal128_fast { return min(); }
};

}
} // namspace std

#endif //BOOST_DECIMAL_DECIMAL128_FAST_HPP
6 changes: 3 additions & 3 deletions include/boost/decimal/decimal32.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2248,9 +2248,9 @@ struct numeric_limits<boost::decimal::decimal32>

// Member functions
static constexpr auto (min) () -> boost::decimal::decimal32 { return {1, min_exponent}; }
static constexpr auto (max) () -> boost::decimal::decimal32 { return {9'999'999, max_exponent}; }
static constexpr auto lowest () -> boost::decimal::decimal32 { return {-9'999'999, max_exponent}; }
static constexpr auto epsilon () -> boost::decimal::decimal32 { return {1, -7}; }
static constexpr auto (max) () -> boost::decimal::decimal32 { return {9'999'999, max_exponent - digits + 1}; }
static constexpr auto lowest () -> boost::decimal::decimal32 { return {9'999'999, max_exponent - digits + 1, true}; }
static constexpr auto epsilon () -> boost::decimal::decimal32 { return {1, -digits + 1}; }
static constexpr auto round_error () -> boost::decimal::decimal32 { return epsilon(); }
static constexpr auto infinity () -> boost::decimal::decimal32 { return boost::decimal::from_bits(boost::decimal::detail::d32_inf_mask); }
static constexpr auto quiet_NaN () -> boost::decimal::decimal32 { return boost::decimal::from_bits(boost::decimal::detail::d32_nan_mask); }
Expand Down
8 changes: 4 additions & 4 deletions include/boost/decimal/decimal32_fast.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -1481,16 +1481,16 @@ struct numeric_limits<boost::decimal::decimal32_fast>

// Member functions
static constexpr auto (min) () -> boost::decimal::decimal32_fast { return {1, min_exponent}; }
static constexpr auto (max) () -> boost::decimal::decimal32_fast { return {9'999'999, max_exponent}; }
static constexpr auto lowest () -> boost::decimal::decimal32_fast { return {-9'999'999, max_exponent}; }
static constexpr auto epsilon () -> boost::decimal::decimal32_fast { return {1, -7}; }
static constexpr auto (max) () -> boost::decimal::decimal32_fast { return {9'999'999, max_exponent - digits + 1}; }
static constexpr auto lowest () -> boost::decimal::decimal32_fast { return {9'999'999, max_exponent - digits + 1, true}; }
static constexpr auto epsilon () -> boost::decimal::decimal32_fast { return {1, -digits + 1}; }
static constexpr auto round_error () -> boost::decimal::decimal32_fast { return epsilon(); }
static constexpr auto infinity () -> boost::decimal::decimal32_fast { return boost::decimal::direct_init(boost::decimal::detail::d32_fast_inf, UINT8_C((0))); }
static constexpr auto quiet_NaN () -> boost::decimal::decimal32_fast { return boost::decimal::direct_init(boost::decimal::detail::d32_fast_qnan, UINT8_C((0))); }
static constexpr auto signaling_NaN() -> boost::decimal::decimal32_fast { return boost::decimal::direct_init(boost::decimal::detail::d32_fast_snan, UINT8_C((0))); }

// With denorm absent returns the same value as min
static constexpr auto denorm_min () -> boost::decimal::decimal32_fast { return {1, min_exponent}; }
static constexpr auto denorm_min () -> boost::decimal::decimal32_fast { return min(); }
};

} // Namespace std
Expand Down
10 changes: 5 additions & 5 deletions include/boost/decimal/decimal64.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2149,18 +2149,18 @@ struct numeric_limits<boost::decimal::decimal64>
static constexpr int digits10 = digits;
static constexpr int max_digits10 = digits;
static constexpr int radix = 10;
static constexpr int min_exponent = -382;
static constexpr int min_exponent = -383;
static constexpr int min_exponent10 = min_exponent;
static constexpr int max_exponent = 385;
static constexpr int max_exponent = 384;
static constexpr int max_exponent10 = max_exponent;
static constexpr bool traps = numeric_limits<std::uint64_t>::traps;
static constexpr bool tinyness_before = true;

// Member functions
static constexpr auto (min) () -> boost::decimal::decimal64 { return {1, min_exponent}; }
static constexpr auto (max) () -> boost::decimal::decimal64 { return {9'999'999'999'999'999, max_exponent}; }
static constexpr auto lowest () -> boost::decimal::decimal64 { return {-9'999'999'999'999'999, max_exponent}; }
static constexpr auto epsilon () -> boost::decimal::decimal64 { return {1, -16}; }
static constexpr auto (max) () -> boost::decimal::decimal64 { return {9'999'999'999'999'999, max_exponent - digits + 1}; }
static constexpr auto lowest () -> boost::decimal::decimal64 { return {9'999'999'999'999'999, max_exponent - digits + 1, true}; }
static constexpr auto epsilon () -> boost::decimal::decimal64 { return {1, -digits + 1}; }
static constexpr auto round_error () -> boost::decimal::decimal64 { return epsilon(); }
static constexpr auto infinity () -> boost::decimal::decimal64 { return boost::decimal::from_bits(boost::decimal::detail::d64_inf_mask); }
static constexpr auto quiet_NaN () -> boost::decimal::decimal64 { return boost::decimal::from_bits(boost::decimal::detail::d64_nan_mask); }
Expand Down
12 changes: 6 additions & 6 deletions include/boost/decimal/decimal64_fast.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -1427,26 +1427,26 @@ struct numeric_limits<boost::decimal::decimal64_fast>
static constexpr int digits10 = digits;
static constexpr int max_digits10 = digits;
static constexpr int radix = 10;
static constexpr int min_exponent = -382;
static constexpr int min_exponent = -383;
static constexpr int min_exponent10 = min_exponent;
static constexpr int max_exponent = 385;
static constexpr int max_exponent = 384;
static constexpr int max_exponent10 = max_exponent;
static constexpr bool traps = numeric_limits<std::uint_fast64_t>::traps;
static constexpr bool tinyness_before = true;

// Member functions
static constexpr auto (min) () -> boost::decimal::decimal64_fast { return {1, min_exponent}; }
static constexpr auto (max) () -> boost::decimal::decimal64_fast { return {9'999'999'999'999'999, max_exponent}; }
static constexpr auto lowest () -> boost::decimal::decimal64_fast { return {-9'999'999'999'999'999, max_exponent}; }
static constexpr auto epsilon () -> boost::decimal::decimal64_fast { return {1, -16}; }
static constexpr auto (max) () -> boost::decimal::decimal64_fast { return {9'999'999'999'999'999, max_exponent - digits + 1}; }
static constexpr auto lowest () -> boost::decimal::decimal64_fast { return {9'999'999'999'999'999, max_exponent - digits + 1, true}; }
static constexpr auto epsilon () -> boost::decimal::decimal64_fast { return {1, -digits + 1}; }
static constexpr auto round_error () -> boost::decimal::decimal64_fast { return epsilon(); }
static constexpr auto infinity () -> boost::decimal::decimal64_fast { return boost::decimal::direct_init_d64(
boost::decimal::detail::d64_fast_inf, 0, false); }
static constexpr auto quiet_NaN () -> boost::decimal::decimal64_fast { return boost::decimal::direct_init_d64(
boost::decimal::detail::d64_fast_qnan, 0, false); }
static constexpr auto signaling_NaN() -> boost::decimal::decimal64_fast { return boost::decimal::direct_init_d64(
boost::decimal::detail::d64_fast_snan, 0, false); }
static constexpr auto denorm_min () -> boost::decimal::decimal64_fast { return {1, boost::decimal::detail::etiny_v<boost::decimal::decimal64>}; }
static constexpr auto denorm_min () -> boost::decimal::decimal64_fast { return min(); }
};

} // namespace std
Expand Down
52 changes: 44 additions & 8 deletions include/boost/decimal/detail/comparison.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,15 +57,36 @@ BOOST_DECIMAL_FORCE_INLINE constexpr auto equality_impl(DecimalType lhs, Decimal

const auto delta_exp {lhs_exp - rhs_exp};

if (delta_exp > detail::precision_v<DecimalType> || delta_exp < -detail::precision_v<DecimalType> ||
((lhs_sig == static_cast<comp_type>(0)) ^ (rhs_sig == static_cast<comp_type>(0))))
if (lhs_sig == 0 && rhs_sig == 0)
{
// The difference in exponent is irrelevant here
return true;
}
if (delta_exp > detail::precision_v<DecimalType> || delta_exp < -detail::precision_v<DecimalType>)
{
return false;
}

// Step 5: Normalize the significand and compare
delta_exp >= 0 ? lhs_sig *= detail::pow10(static_cast<comp_type>(delta_exp)) :
rhs_sig *= detail::pow10(static_cast<comp_type>(-delta_exp));
// Instead of multiplying the larger number, divide the smaller one
if (delta_exp >= 0)
{
// Check if we can divide rhs_sig safely
if (delta_exp > 0 && rhs_sig % detail::pow10(static_cast<comp_type>(delta_exp)) != 0)
{
return false;
}
rhs_sig /= detail::pow10(static_cast<comp_type>(delta_exp));
}
else
{
// Check if we can divide lhs_sig safely
if (lhs_sig % detail::pow10(static_cast<comp_type>(-delta_exp)) != 0)
{
return false;
}
lhs_sig /= detail::pow10(static_cast<comp_type>(-delta_exp));
}

return lhs_sig == rhs_sig;
}
Expand Down Expand Up @@ -93,19 +114,34 @@ constexpr auto equal_parts_impl(T1 lhs_sig, U1 lhs_exp, bool lhs_sign,

// Check the value of delta exp to avoid to large a value for pow10
// Also if only one of the significands is 0 then we know the values have to be mismatched
if (delta_exp > detail::precision_v<DecimalType> || delta_exp < -detail::precision_v<DecimalType> ||
((new_lhs_sig == static_cast<comp_type>(0)) ^ (new_rhs_sig == static_cast<comp_type>(0))))
if (new_lhs_sig == static_cast<comp_type>(0) && new_rhs_sig == static_cast<comp_type>(0))
{
return true;
}
if (delta_exp > detail::precision_v<DecimalType> || delta_exp < -detail::precision_v<DecimalType>)
{
return false;
}

// Step 5: Normalize the significand and compare
// Instead of multiplying the larger number, divide the smaller one
if (delta_exp >= 0)
{
new_lhs_sig *= detail::pow10(static_cast<comp_type>(delta_exp));
// Check if we can divide rhs_sig safely
if (delta_exp > 0 && new_rhs_sig % detail::pow10(static_cast<comp_type>(delta_exp)) != 0)
{
return false;
}
new_rhs_sig /= detail::pow10(static_cast<comp_type>(delta_exp));
}
else
{
new_rhs_sig *= detail::pow10(static_cast<comp_type>(-delta_exp));
// Check if we can divide lhs_sig safely
if (new_lhs_sig % detail::pow10(static_cast<comp_type>(-delta_exp)) != 0)
{
return false;
}
new_lhs_sig /= detail::pow10(static_cast<comp_type>(-delta_exp));
}

#ifdef BOOST_DECIMAL_DEBUG_EQUAL
Expand Down
2 changes: 1 addition & 1 deletion include/boost/decimal/detail/config.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,7 @@ typedef unsigned __int128 uint128_t;
#endif

// https://github.com/llvm/llvm-project/issues/55638
#if defined(__clang__) && __cplusplus > 202002L
#if defined(__clang__) && __cplusplus > 202002L && __clang_major__ < 17
# undef BOOST_DECIMAL_IS_CONSTANT_EVALUATED
# define BOOST_DECIMAL_IS_CONSTANT_EVALUATED(x) false
# define BOOST_DECIMAL_NO_CONSTEVAL_DETECTION
Expand Down
1 change: 1 addition & 0 deletions test/Jamfile
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ run test_implicit_integral_conversion.cpp ;
run test_laguerre.cpp ;
run test_legendre.cpp ;
run test_literals.cpp ;
run test_limits.cpp ;
run test_lgamma.cpp ;
run test_log.cpp ;
run test_log1p.cpp ;
Expand Down
23 changes: 0 additions & 23 deletions test/test_decimal32.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -261,15 +261,6 @@ void test_addition()
BOOST_TEST(isinf(one + inf_val));
BOOST_TEST(isnan(inf_val + qnan_val));
BOOST_TEST(isnan(qnan_val + inf_val));

// Overflow
constexpr decimal32 max_val((std::numeric_limits<decimal32>::max)());
if (!BOOST_TEST(isinf(max_val + one)))
{
// LCOV_EXCL_START
std::cerr << std::bitset<32>(to_bits(max_val + one)) << std::endl;
// LCOV_EXCL_STOP
}
}

void test_subtraction()
Expand Down Expand Up @@ -320,20 +311,6 @@ void test_subtraction()
BOOST_TEST(isinf(one - inf_val));
BOOST_TEST(isnan(inf_val - qnan_val));
BOOST_TEST(isnan(qnan_val - inf_val));

// Why does MSVC 14.1 warn about unary minus but nothing else does?
#ifdef _MSC_VER
# pragma warning(push)
# pragma warning(disable: 4146)
#endif

// Underflow
constexpr decimal32 lowest_val(std::numeric_limits<decimal32>::lowest());
BOOST_TEST(isinf(lowest_val - one));

#ifdef _MSC_VER
# pragma warning(pop)
#endif
}

void test_multiplicatiom()
Expand Down
Loading
Loading