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
8 changes: 4 additions & 4 deletions doc/modules/ROOT/pages/cmath.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ All of these functions are impacted by the global rounding mode as described in
| https://en.cppreference.com/w/cpp/numeric/math/fma[fma] | Fused Multiply - Add
| https://en.cppreference.com/w/cpp/numeric/math/fmax[fmax] | Returns maximum value
| https://en.cppreference.com/w/cpp/numeric/math/fmin[fmin] | Returns minimum value
| https://en.cppreference.com/w/cpp/numeric/math/fdim[fdim] | Returns unsigned difference of two values
| https://en.cppreference.com/w/cpp/numeric/math/fdim[fdim] | Returns positive difference of two values
| https://en.cppreference.com/w/cpp/numeric/math/nan[nan] | Generates Quiet NANs with Payload
| https://en.cppreference.com/w/cpp/numeric/math/nan[snan] | Generates Signaling NANs with Payload (Non-Standard)
|===
Expand Down Expand Up @@ -60,13 +60,13 @@ template <typename DecimalType>
constexpr DecimalType fma(DecimalType x, DecimalType y, DecimalType z) noexcept;

template <typename DecimalType>
constexpr DecimalType fmax(DecimalType x, DecimalType y, int* quo) noexcept;
constexpr DecimalType fmax(DecimalType x, DecimalType y) noexcept;

template <typename DecimalType>
constexpr DecimalType fmin(DecimalType x, DecimalType y, int* quo) noexcept;
constexpr DecimalType fmin(DecimalType x, DecimalType y) noexcept;

template <typename DecimalType>
constexpr DecimalType fdim(DecimalType x, DecimalType y, int* quo) noexcept;
constexpr DecimalType fdim(DecimalType x, DecimalType y) noexcept;

constexpr decimal32_t nand32(const char* arg) noexcept;
constexpr decimal64_t nand64(const char* arg) noexcept;
Expand Down
13 changes: 2 additions & 11 deletions include/boost/decimal/detail/cmath/fdim.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,17 +25,8 @@ constexpr auto fdim(const T x, const T y) noexcept
{
constexpr T zero {0, 0};

#ifndef BOOST_DECIMAL_FAST_MATH
if (isnan(x) || isinf(x))
{
return x;
}
else if (isnan(y))
{
return y;
}
#endif

// A NaN fails the compare, and the subtraction gives it back as a quiet NaN.
// An infinite x takes the same path as a finite x: +0 when y >= x, else x - y.
if (y >= x)
{
return zero;
Expand Down
1 change: 1 addition & 0 deletions test/Jamfile
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@ run github_issue_1504.cpp ;
run github_issue_1516.cpp ;
run github_issue_1520.cpp ;
run github_issue_1522.cpp ;
run github_issue_1525.cpp ;

run link_1.cpp link_2.cpp link_3.cpp ;
run quick.cpp ;
Expand Down
80 changes: 80 additions & 0 deletions test/github_issue_1525.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
// Copyright 2026 Shen-Ta Hsieh
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
//
// See: https://github.com/boostorg/decimal/issues/1525

#include <boost/decimal.hpp>
#include <boost/core/lightweight_test.hpp>
#include <limits>

using namespace boost::decimal;

template <typename T>
bool is_pos_zero(const T x)
{
return x == 0 && !signbit(x);
}

template <typename T>
bool is_quiet_nan(const T x)
{
return isnan(x) && !issignaling(x);
}

// fdim(x, y) is +0 when x <= y and x - y when x > y, also for an infinite x or y.
// A NaN y gives NaN.
template <typename T>
void test_infinities()
{
const auto inf {std::numeric_limits<T>::infinity()};
const auto nan {std::numeric_limits<T>::quiet_NaN()};

BOOST_TEST(is_pos_zero(fdim(-inf, T(1))));
BOOST_TEST(is_pos_zero(fdim(-inf, -inf)));
BOOST_TEST(is_pos_zero(fdim(inf, inf)));
BOOST_TEST(isnan(fdim(inf, nan)));
BOOST_TEST(isnan(fdim(-inf, nan)));
BOOST_TEST_EQ(fdim(inf, T(1)), inf);
BOOST_TEST_EQ(fdim(inf, -inf), inf);
BOOST_TEST_EQ(fdim(T(1), -inf), inf);
BOOST_TEST(is_pos_zero(fdim(T(1), inf)));
}

// fdim gives a quiet NaN when x or y is a signaling NaN
template <typename T>
void test_signaling_nan()
{
const auto snan {std::numeric_limits<T>::signaling_NaN()};
const auto inf {std::numeric_limits<T>::infinity()};
const auto nan {std::numeric_limits<T>::quiet_NaN()};

for (const auto other : {T(1), T(-1), T(0), inf, -inf, nan})
{
BOOST_TEST(is_quiet_nan(fdim(snan, other)));
BOOST_TEST(is_quiet_nan(fdim(other, snan)));
BOOST_TEST(is_quiet_nan(fdim(-snan, other)));
BOOST_TEST(is_quiet_nan(fdim(other, -snan)));
}
}

template <typename T>
void test()
{
test_infinities<T>();
test_signaling_nan<T>();
}

int main()
{
#ifndef BOOST_DECIMAL_FAST_MATH
test<decimal32_t>();
test<decimal64_t>();
test<decimal128_t>();
test<decimal_fast32_t>();
test<decimal_fast64_t>();
test<decimal_fast128_t>();
#endif

return boost::report_errors();
}
Loading