Ensure remainder has correct sign when the result is zero.

Also ensure float128 specializations of eval_signbit are actually called.
Change return type of signbit to bool to match std::signbit and update docs.
Add test case.
Fixes https://github.com/boostorg/multiprecision/issues/426.
This commit is contained in:
jzmaddock
2022-02-01 19:02:02 +00:00
parent d7a0a2baed
commit a8ab907e20
6 changed files with 67 additions and 7 deletions

View File

@@ -452,7 +452,7 @@ are either trivial or are forwarded to the Boost.Math implementations by default
The full list of these functions is:
int sign (const ``['number-or-expression-template-type]``&);
int signbit (const ``['number-or-expression-template-type]``&);
bool signbit (const ``['number-or-expression-template-type]``&);
``['number]`` changesign (const ``['number-or-expression-template-type]``&);
``['number]`` copysign (const ``['number-or-expression-template-type]``&, const ``['number-or-expression-template-type]``&);
``['number]`` asinh (const ``['number-or-expression-template-type]``&);

View File

@@ -199,7 +199,7 @@
bool isinf (const ``['number-or-expression-template-type]``&);
bool isnan (const ``['number-or-expression-template-type]``&);
bool isnormal (const ``['number-or-expression-template-type]``&);
int signbit (const ``['number-or-expression-template-type]``&);
bool signbit (const ``['number-or-expression-template-type]``&);
bool isgreater (const ``['number-or-expression-template-type]``&, const ``['number-or-expression-template-type]``&);
bool isgreaterequal(const ``['number-or-expression-template-type]``&, const ``['number-or-expression-template-type]``&);
@@ -623,7 +623,7 @@ that allows arithmetic to be performed on native integer types producing an exte
bool isinf (const ``['number-or-expression-template-type]``&);
bool isnan (const ``['number-or-expression-template-type]``&);
bool isnormal (const ``['number-or-expression-template-type]``&);
int signbit (const ``['number-or-expression-template-type]``&);
bool signbit (const ``['number-or-expression-template-type]``&);
bool isgreater (const ``['number-or-expression-template-type]``&, const ``['number-or-expression-template-type]``&);
bool isgreaterequal(const ``['number-or-expression-template-type]``&, const ``['number-or-expression-template-type]``&);

View File

@@ -1328,6 +1328,11 @@ inline BOOST_MP_CXX14_CONSTEXPR void eval_remquo(T& result, const T& a, const T&
eval_convert_to(pi, n);
eval_multiply(n, b);
eval_subtract(result, a, n);
if (eval_is_zero(result))
{
if (eval_signbit(a))
result.negate();
}
}
template <class T, class A>
inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<boost::multiprecision::detail::is_arithmetic<A>::value, void>::type eval_remquo(T& result, const T& x, const A& a, int* pi)
@@ -2203,16 +2208,16 @@ inline BOOST_MP_CXX14_CONSTEXPR int sign BOOST_PREVENT_MACRO_SUBSTITUTION(const
}
template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
inline BOOST_MP_CXX14_CONSTEXPR int signbit BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& arg)
inline BOOST_MP_CXX14_CONSTEXPR bool signbit BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& arg)
{
using default_ops::eval_signbit;
return eval_signbit(arg.backend());
return static_cast<bool>(eval_signbit(arg.backend()));
}
template <class tag, class A1, class A2, class A3, class A4>
inline BOOST_MP_CXX14_CONSTEXPR int signbit BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& arg)
inline BOOST_MP_CXX14_CONSTEXPR bool signbit BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& arg)
{
using value_type = typename multiprecision::detail::expression<tag, A1, A2, A3, A4>::result_type;
return signbit BOOST_PREVENT_MACRO_SUBSTITUTION(value_type(arg));
return static_cast<bool>(signbit BOOST_PREVENT_MACRO_SUBSTITUTION(value_type(arg)));
}
template <class Backend, multiprecision::expression_template_option ExpressionTemplates>
inline BOOST_MP_CXX14_CONSTEXPR multiprecision::number<Backend, ExpressionTemplates> changesign BOOST_PREVENT_MACRO_SUBSTITUTION(const multiprecision::number<Backend, ExpressionTemplates>& arg)

View File

@@ -723,6 +723,8 @@ inline boost::multiprecision::number<boost::multiprecision::backends::float128_b
return ::copysignq(a.backend().value(), b.backend().value());
}
namespace backends {
inline void eval_remainder(float128_backend& result, const float128_backend& a, const float128_backend& b)
{
result.value() = remainderq(a.value(), b.value());
@@ -731,6 +733,8 @@ inline void eval_remainder(float128_backend& result, const float128_backend& a,
{
result.value() = remquoq(a.value(), b.value(), pi);
}
} // namespace backends
#endif
} // namespace multiprecision

View File

@@ -1134,6 +1134,7 @@ test-suite misc :
[ run git_issue_175.cpp ]
[ run git_issue_248.cpp ]
[ run git_issue_265.cpp : : : [ check-target-builds ../config//has_mpfr : <source>gmp <source>mpfr : <build>no ] ]
[ run git_issue_426.cpp : : : [ check-target-builds ../config//has_mpfr : <source>gmp <source>mpfr <define>TEST_MPFR ] [ check-target-builds ../config//has_float128 : <source>quadmath <define>TEST_FLOAT128 ] ]
[ run git_issue_277.cpp ]
[ run git_issue_313.cpp ]
[ compile git_issue_98.cpp :

50
test/git_issue_426.cpp Normal file
View File

@@ -0,0 +1,50 @@
///////////////////////////////////////////////////////////////////////////////
// Copyright 2019 John Maddock. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <boost/multiprecision/cpp_bin_float.hpp>
#ifdef TEST_MPFR
#include <boost/multiprecision/mpfr.hpp>
#endif
#ifdef TEST_FLOAT128
#include <boost/multiprecision/float128.hpp>
#endif
#include "test.hpp"
template <class T>
void test()
{
T d = 360;
for (int i = 2; i >= -2; --i)
{
T x = i * d;
T y = remainder(x, d);
if (y == 0)
BOOST_CHECK_EQUAL(signbit(y), signbit(x));
if (i == 0)
{
x = -x;
y = remainder(x, d);
if (y == 0)
BOOST_CHECK_EQUAL(signbit(y), signbit(x));
}
}
}
int main()
{
test<boost::multiprecision::cpp_bin_float_50>();
// No signed zero:
//test<boost::multiprecision::cpp_dec_float_50>();
//test<boost::multiprecision::mpf_float_50>();
#ifdef TEST_MPFR
test<boost::multiprecision::mpfr_float_50>();
#endif
#ifdef TEST_FLOAT128
test<boost::multiprecision::float128>();
#endif
return boost::report_errors();
}