Skip to content

Commit

Permalink
Merge pull request #605 from boostorg/issue604
Browse files Browse the repository at this point in the history
Fix up default fmod to perform post-condition checking.
  • Loading branch information
jzmaddock authored Mar 1, 2024
2 parents f0319ec + 062503f commit 42a3edf
Show file tree
Hide file tree
Showing 3 changed files with 125 additions and 0 deletions.
24 changes: 24 additions & 0 deletions include/boost/multiprecision/detail/default_ops.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -1295,6 +1295,30 @@ inline BOOST_MP_CXX14_CONSTEXPR void eval_fmod(T& result, const T& a, const T& b
eval_floor(n, result);
eval_multiply(n, b);
eval_subtract(result, a, n);
if (eval_get_sign(result) != 0)
{
//
// Sanity check, that due to rounding errors in division,
// we haven't accidently calculated the wrong value:
// See https://github.com/boostorg/multiprecision/issues/604 for an example.
//
if (eval_get_sign(result) == eval_get_sign(b))
{
if (result.compare(b) >= 0)
{
eval_subtract(result, b);
}
}
else
{
n = b;
n.negate();
if (result.compare(n) >= 0)
{
eval_subtract(result, n);
}
}
}
}
template <class T, class A>
inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<boost::multiprecision::detail::is_arithmetic<A>::value, void>::type eval_fmod(T& result, const T& x, const A& a)
Expand Down
5 changes: 5 additions & 0 deletions test/Jamfile.v2
Original file line number Diff line number Diff line change
Expand Up @@ -1235,6 +1235,11 @@ test-suite misc :
[ run git_issue_573.cpp : : : <toolset>msvc:<cxxflags>-sdl ]
[ run git_issue_576.cpp : : : [ check-target-builds ../config//has_float128 : <define>TEST_FLOAT128 <source>quadmath : ] ]
[ run git_issue_595.cpp : : : [ check-target-builds ../config//has_mpfr : <source>gmp <source>mpfr : <build>no ] ]
[ run git_issue_604.cpp : : : [ check-target-builds ../config//has_mpfr : <source>gmp <source>mpfr <define>TEST_MPFR_50 ]
[ check-target-builds ../config//has_gmp : <source>gmp <define>TEST_MPF_50 ]
[ check-target-builds ../config//has_float128 : <source>quadmath <define>TEST_FLOAT128 ]
<define>TEST_CPP_DEC_FLOAT
<define>TEST_CPP_BIN_FLOAT ]
[ compile git_issue_98.cpp :
[ check-target-builds ../config//has_float128 : <define>TEST_FLOAT128 <source>quadmath : ]
[ check-target-builds ../config//has_gmp : <define>TEST_GMP <source>gmp : ]
Expand Down
96 changes: 96 additions & 0 deletions test/git_issue_604.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
///////////////////////////////////////////////////////////////////////////////
// Copyright 2024 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)

#if !defined(TEST_MPF_50) && !defined(TEST_CPP_DEC_FLOAT) && !defined(TEST_MPFR_50) && !defined(TEST_FLOAT128) && !defined(TEST_CPP_BIN_FLOAT)
#define TEST_MPF_50
#define TEST_MPFR_50
#define TEST_CPP_DEC_FLOAT
#define TEST_FLOAT128
#define TEST_CPP_BIN_FLOAT

#ifdef _MSC_VER
#pragma message("CAUTION!!: No backend type specified so testing everything.... this will take some time!!")
#endif
#ifdef __GNUC__
#pragma warning "CAUTION!!: No backend type specified so testing everything.... this will take some time!!"
#endif

#endif

#if defined(TEST_MPF_50)
#include <boost/multiprecision/gmp.hpp>
#endif
#if defined(TEST_MPFR_50)
#include <boost/multiprecision/mpfr.hpp>
#endif
#ifdef TEST_CPP_DEC_FLOAT
#include <boost/multiprecision/cpp_dec_float.hpp>
#endif
#ifdef TEST_FLOAT128
#include <boost/multiprecision/float128.hpp>
#endif
#ifdef TEST_CPP_BIN_FLOAT
#include <boost/multiprecision/cpp_bin_float.hpp>
#endif

#include <iostream>
#include "test.hpp"

template <class T>
void test()
{
{
const T val1{6};
const T val2{3};
T r = boost::multiprecision::fmod(val1, val2);
BOOST_CHECK_EQUAL(r, T(0));
}
{
const T val1{-6};
const T val2{3};
T r = boost::multiprecision::fmod(val1, val2);
BOOST_CHECK_EQUAL(r, T(0));
}
{
const T val1{6};
const T val2{-3};
T r = boost::multiprecision::fmod(val1, val2);
BOOST_CHECK_EQUAL(r, T(0));
}
{
const T val1{-6};
const T val2{-3};
T r = boost::multiprecision::fmod(val1, val2);
BOOST_CHECK_EQUAL(r, T(0));
}
}



int main()
{
using namespace boost::multiprecision;

#ifdef TEST_MPF_50
test<boost::multiprecision::mpf_float_50>();
test<boost::multiprecision::mpf_float_100>();
#endif
#ifdef TEST_MPFR_50
test<boost::multiprecision::mpfr_float_50>();
test<boost::multiprecision::mpfr_float_100>();
#endif
#ifdef TEST_CPP_DEC_FLOAT
test<boost::multiprecision::cpp_dec_float_50>();
test<boost::multiprecision::cpp_dec_float_100>();
#endif
#ifdef TEST_FLOAT128
test<boost::multiprecision::float128>();
#endif
#ifdef TEST_CPP_BIN_FLOAT
test<boost::multiprecision::cpp_bin_float_50>();
test<boost::multiprecision::number<boost::multiprecision::cpp_bin_float<35, boost::multiprecision::digit_base_10, std::allocator<char>, long long> > >();
#endif
return boost::report_errors();
}

0 comments on commit 42a3edf

Please sign in to comment.