Skip to content

Commit

Permalink
Merge pull request #243 from bluescarni/pr/backports
Browse files Browse the repository at this point in the history
More backports from #242
  • Loading branch information
bluescarni authored May 26, 2020
2 parents f700472 + deecb49 commit eefa801
Show file tree
Hide file tree
Showing 9 changed files with 243 additions and 58 deletions.
3 changes: 3 additions & 0 deletions doc/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ Changelog
New
~~~

- Implement additional three-way comparison functions
for :cpp:class:`~mppp::real`
(`#243 <https://github.com/bluescarni/mppp/pull/243>`__).
- Add the :cpp:func:`~mppp::set_ui_2exp()` and :cpp:func:`~mppp::set_si_2exp()`
functions for :cpp:class:`~mppp::real`, and implement constructors
from an integral multiple of a power of 2
Expand Down
128 changes: 86 additions & 42 deletions doc/real.rst
Original file line number Diff line number Diff line change
Expand Up @@ -667,6 +667,14 @@ The real class

:return: a reference to ``this``.

.. cpp:function:: real &sqr()

.. versionadded:: 0.19

Square ``this`` in place.

:return: a reference to ``this``.

.. cpp:function:: real &sqrt()
.. cpp:function:: real &rec_sqrt()
.. cpp:function:: real &sqrt1pm1()
Expand Down Expand Up @@ -702,14 +710,6 @@ The real class
:exception std\:\:invalid_argument: if the conversion between Arb and MPFR types
fails because of (unlikely) overflow conditions.

.. cpp:function:: real &sqr()

.. versionadded:: 0.19

Square ``this`` in place.

:return: a reference to ``this``.

.. cpp:function:: real &sin()
.. cpp:function:: real &cos()
.. cpp:function:: real &tan()
Expand Down Expand Up @@ -954,6 +954,11 @@ Types
Concepts
--------

.. cpp:concept:: template <typename T> mppp::cvr_real

This concept is satisfied if the type ``T``, after the removal of reference and cv qualifiers,
is the same as :cpp:class:`mppp::real`.

.. cpp:concept:: template <typename T> mppp::real_interoperable

This concept is satisfied if the type ``T`` can interoperate with :cpp:class:`~mppp::real`.
Expand All @@ -964,11 +969,6 @@ Concepts
* a :cpp:class:`~mppp::rational`, or
* :cpp:class:`~mppp::real128`.

.. cpp:concept:: template <typename T> mppp::cvr_real

This concept is satisfied if the type ``T``, after the removal of reference and cv qualifiers,
is the same as :cpp:class:`mppp::real`.

.. cpp:concept:: template <typename... Args> mppp::real_set_args

This concept is satisfied if the types in the parameter pack ``Args``
Expand Down Expand Up @@ -1310,6 +1310,34 @@ Arithmetic

:return: *x* multiplied/divided by :math:`2^n`.

.. cpp:function:: template <mppp::cvr_real T> mppp::real &mppp::sqr(mppp::real &rop, T &&op)

.. versionadded:: 0.19

Binary :cpp:class:`~mppp::real` squaring.

This function will compute the square of *op* and store it
into *rop*. The precision of the result will be equal to the precision
of *op*.

:param rop: the return value.
:param op: the operand.

:return: a reference to *rop*.

.. cpp:function:: template <mppp::cvr_real T> mppp::real mppp::sqr(T &&r)

.. versionadded:: 0.19

Unary :cpp:class:`~mppp::real` squaring.

This function will compute and return the square of *r*.
The precision of the result will be equal to the precision of *r*.

:param r: the operand.

:return: the square of *r*.

.. _real_comparison:

Comparison
Expand Down Expand Up @@ -1380,6 +1408,50 @@ Comparison

:exception std\:\:domain_error: if at least one of the operands is NaN.

.. cpp:function:: int mppp::cmpabs(const mppp::real &a, const mppp::real &b)

.. versionadded:: 0.20

Three-way comparison of absolute values.

This function will compare *a* and *b*, returning:

* zero if :math:`\left|a\right|=\left|b\right|`,
* a negative value if :math:`\left|a\right|<\left|b\right|`,
* a positive value if :math:`\left|a\right|>\left|b\right|`.

If at least one NaN value is involved in the comparison, an error will be raised.

:param a: the first operand.
:param b: the second operand.

:return: an integral value expressing how the absolute values of *a* and *b* compare.

:exception std\:\:domain_error: if at least one of the operands is NaN.

.. cpp:function:: int mppp::cmp_ui_2exp(const mppp::real &a, unsigned long n, mpfr_exp_t e)
.. cpp:function:: int mppp::cmp_si_2exp(const mppp::real &a, long n, mpfr_exp_t e)

.. versionadded:: 0.20

Comparison with integral multiples of powers of 2.

This function will compare *a* to :math:`n\times 2^e`, returning:

* zero if :math:`a=n\times 2^e`,
* a negative value if :math:`a<n\times 2^e`,
* a positive value if :math:`a>n\times 2^e`.

If *a* is NaN, an error will be raised.

:param a: the first operand.
:param n: the integral multiplier.
:param e: the power of 2.

:return: an integral value expressing how *a* compares to :math:`n\times 2^e`.

:exception std\:\:domain_error: if *a* is NaN.

.. cpp:function:: bool mppp::real_equal_to(const mppp::real &a, const mppp::real &b)

Equality predicate with special handling for NaN.
Expand Down Expand Up @@ -1634,34 +1706,6 @@ Exponentiation

:return: *op1* raised to the power of *op2*.

.. cpp:function:: template <mppp::cvr_real T> mppp::real &mppp::sqr(mppp::real &rop, T &&op)

.. versionadded:: 0.19

Binary :cpp:class:`~mppp::real` squaring.

This function will compute the square of *op* and store it
into *rop*. The precision of the result will be equal to the precision
of *op*.

:param rop: the return value.
:param op: the operand.

:return: a reference to *rop*.

.. cpp:function:: template <mppp::cvr_real T> mppp::real mppp::sqr(T &&r)

.. versionadded:: 0.19

Unary :cpp:class:`~mppp::real` squaring.

This function will compute and return the square of *r*.
The precision of the result will be equal to the precision of *r*.

:param r: the operand.

:return: the square of *r*.

.. _real_trig:

Trigonometry
Expand Down Expand Up @@ -2503,7 +2547,7 @@ Input/Output

:return: a reference to *os*.

:exception unspecified: any exception thrown by :cpp:func`mppp::real::to_string()`.
:exception unspecified: any exception thrown by :cpp:func:`mppp::real::to_string()`.

.. _real_operators:

Expand Down
57 changes: 41 additions & 16 deletions include/mp++/real.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -1553,8 +1553,8 @@ template <typename T, cvr_real_enabler<T> = 0>
#endif
inline real mul_2ui(T &&x, unsigned long n)
{
auto mul_2ui_wrapper = [n](::mpfr_t r, const ::mpfr_t o) { ::mpfr_mul_2ui(r, o, n, MPFR_RNDN); };
return detail::mpfr_nary_op_return_impl<false>(0, mul_2ui_wrapper, std::forward<T>(x));
auto wrapper = [n](::mpfr_t r, const ::mpfr_t o) { ::mpfr_mul_2ui(r, o, n, MPFR_RNDN); };
return detail::mpfr_nary_op_return_impl<false>(0, wrapper, std::forward<T>(x));
}

#if defined(MPPP_HAVE_CONCEPTS)
Expand All @@ -1564,8 +1564,8 @@ template <typename T, cvr_real_enabler<T> = 0>
#endif
inline real &mul_2ui(real &rop, T &&x, unsigned long n)
{
auto mul_2ui_wrapper = [n](::mpfr_t r, const ::mpfr_t o) { ::mpfr_mul_2ui(r, o, n, MPFR_RNDN); };
return detail::mpfr_nary_op_impl<false>(0, mul_2ui_wrapper, rop, std::forward<T>(x));
auto wrapper = [n](::mpfr_t r, const ::mpfr_t o) { ::mpfr_mul_2ui(r, o, n, MPFR_RNDN); };
return detail::mpfr_nary_op_impl<false>(0, wrapper, rop, std::forward<T>(x));
}

#if defined(MPPP_HAVE_CONCEPTS)
Expand All @@ -1575,8 +1575,8 @@ template <typename T, cvr_real_enabler<T> = 0>
#endif
inline real mul_2si(T &&x, long n)
{
auto mul_2si_wrapper = [n](::mpfr_t r, const ::mpfr_t o) { ::mpfr_mul_2si(r, o, n, MPFR_RNDN); };
return detail::mpfr_nary_op_return_impl<false>(0, mul_2si_wrapper, std::forward<T>(x));
auto wrapper = [n](::mpfr_t r, const ::mpfr_t o) { ::mpfr_mul_2si(r, o, n, MPFR_RNDN); };
return detail::mpfr_nary_op_return_impl<false>(0, wrapper, std::forward<T>(x));
}

#if defined(MPPP_HAVE_CONCEPTS)
Expand All @@ -1586,8 +1586,8 @@ template <typename T, cvr_real_enabler<T> = 0>
#endif
inline real &mul_2si(real &rop, T &&x, long n)
{
auto mul_2si_wrapper = [n](::mpfr_t r, const ::mpfr_t o) { ::mpfr_mul_2si(r, o, n, MPFR_RNDN); };
return detail::mpfr_nary_op_impl<false>(0, mul_2si_wrapper, rop, std::forward<T>(x));
auto wrapper = [n](::mpfr_t r, const ::mpfr_t o) { ::mpfr_mul_2si(r, o, n, MPFR_RNDN); };
return detail::mpfr_nary_op_impl<false>(0, wrapper, rop, std::forward<T>(x));
}

#if defined(MPPP_HAVE_CONCEPTS)
Expand All @@ -1597,8 +1597,8 @@ template <typename T, cvr_real_enabler<T> = 0>
#endif
inline real div_2ui(T &&x, unsigned long n)
{
auto div_2ui_wrapper = [n](::mpfr_t r, const ::mpfr_t o) { ::mpfr_div_2ui(r, o, n, MPFR_RNDN); };
return detail::mpfr_nary_op_return_impl<false>(0, div_2ui_wrapper, std::forward<T>(x));
auto wrapper = [n](::mpfr_t r, const ::mpfr_t o) { ::mpfr_div_2ui(r, o, n, MPFR_RNDN); };
return detail::mpfr_nary_op_return_impl<false>(0, wrapper, std::forward<T>(x));
}

#if defined(MPPP_HAVE_CONCEPTS)
Expand All @@ -1608,8 +1608,8 @@ template <typename T, cvr_real_enabler<T> = 0>
#endif
inline real &div_2ui(real &rop, T &&x, unsigned long n)
{
auto div_2ui_wrapper = [n](::mpfr_t r, const ::mpfr_t o) { ::mpfr_div_2ui(r, o, n, MPFR_RNDN); };
return detail::mpfr_nary_op_impl<false>(0, div_2ui_wrapper, rop, std::forward<T>(x));
auto wrapper = [n](::mpfr_t r, const ::mpfr_t o) { ::mpfr_div_2ui(r, o, n, MPFR_RNDN); };
return detail::mpfr_nary_op_impl<false>(0, wrapper, rop, std::forward<T>(x));
}

#if defined(MPPP_HAVE_CONCEPTS)
Expand All @@ -1619,8 +1619,8 @@ template <typename T, cvr_real_enabler<T> = 0>
#endif
inline real div_2si(T &&x, long n)
{
auto div_2si_wrapper = [n](::mpfr_t r, const ::mpfr_t o) { ::mpfr_div_2si(r, o, n, MPFR_RNDN); };
return detail::mpfr_nary_op_return_impl<false>(0, div_2si_wrapper, std::forward<T>(x));
auto wrapper = [n](::mpfr_t r, const ::mpfr_t o) { ::mpfr_div_2si(r, o, n, MPFR_RNDN); };
return detail::mpfr_nary_op_return_impl<false>(0, wrapper, std::forward<T>(x));
}

#if defined(MPPP_HAVE_CONCEPTS)
Expand All @@ -1630,8 +1630,8 @@ template <typename T, cvr_real_enabler<T> = 0>
#endif
inline real &div_2si(real &rop, T &&x, long n)
{
auto div_2si_wrapper = [n](::mpfr_t r, const ::mpfr_t o) { ::mpfr_div_2si(r, o, n, MPFR_RNDN); };
return detail::mpfr_nary_op_impl<false>(0, div_2si_wrapper, rop, std::forward<T>(x));
auto wrapper = [n](::mpfr_t r, const ::mpfr_t o) { ::mpfr_div_2si(r, o, n, MPFR_RNDN); };
return detail::mpfr_nary_op_impl<false>(0, wrapper, rop, std::forward<T>(x));
}

// Detect NaN.
Expand Down Expand Up @@ -1691,6 +1691,13 @@ inline bool signbit(const real &r)
// Comparison.
MPPP_DLL_PUBLIC int cmp(const real &, const real &);

// Comparison of absolute values.
MPPP_DLL_PUBLIC int cmpabs(const real &, const real &);

// Comparison with integral multiples of powers of 2.
MPPP_DLL_PUBLIC int cmp_ui_2exp(const real &, unsigned long, ::mpfr_exp_t);
MPPP_DLL_PUBLIC int cmp_si_2exp(const real &, long, ::mpfr_exp_t);

// Equality predicate with special NaN handling.
MPPP_DLL_PUBLIC bool real_equal_to(const real &, const real &);

Expand Down Expand Up @@ -1892,6 +1899,15 @@ inline real dispatch_real_pow(T &&a, const U &n)
}
}

// Special casing for bool
template <typename T, enable_if_t<is_cvr_real<T>::value, int> = 0>
inline real dispatch_real_pow(T &&a, const bool &n)
{
auto wrapper = [n](::mpfr_t r, const ::mpfr_t o) { ::mpfr_pow_ui(r, o, static_cast<unsigned long>(n), MPFR_RNDN); };

return mpfr_nary_op_return_impl<false>(real_deduce_precision(n), wrapper, std::forward<T>(a));
}

// real-signed integral.
template <typename T, typename U, enable_if_t<conjunction<is_cvr_real<T>, is_cpp_signed_integral<U>>::value, int> = 0>
inline real dispatch_real_pow(T &&a, const U &n)
Expand Down Expand Up @@ -1951,6 +1967,15 @@ inline real dispatch_real_pow(const T &n, U &&a)
}
}

// Special casing for bool.
template <typename T, enable_if_t<is_cvr_real<T>::value, int> = 0>
inline real dispatch_real_pow(const bool &n, T &&a)
{
auto wrapper = [n](::mpfr_t r, const ::mpfr_t o) { ::mpfr_ui_pow(r, static_cast<unsigned long>(n), o, MPFR_RNDN); };

return mpfr_nary_op_return_impl<false>(real_deduce_precision(n), wrapper, std::forward<T>(a));
}

} // namespace detail

// Binary exponentiation.
Expand Down
35 changes: 35 additions & 0 deletions src/real.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2566,6 +2566,41 @@ int cmp(const real &a, const real &b)
return retval;
}

// Three-way comparison of absolute values.
int cmpabs(const real &a, const real &b)
{
::mpfr_clear_erangeflag();
auto retval = ::mpfr_cmpabs(a.get_mpfr_t(), b.get_mpfr_t());
if (mppp_unlikely(::mpfr_erangeflag_p())) {
::mpfr_clear_erangeflag();
throw std::domain_error("Cannot compare the absolute values of two reals if at least one of them is NaN");
}
return retval;
}

// Comparison with n*2**e.
int cmp_ui_2exp(const real &x, unsigned long n, ::mpfr_exp_t e)
{
::mpfr_clear_erangeflag();
auto retval = ::mpfr_cmp_ui_2exp(x.get_mpfr_t(), n, e);
if (mppp_unlikely(::mpfr_erangeflag_p())) {
::mpfr_clear_erangeflag();
throw std::domain_error("Cannot compare a real NaN to an integral multiple of a power of 2");
}
return retval;
}

int cmp_si_2exp(const real &x, long n, ::mpfr_exp_t e)
{
::mpfr_clear_erangeflag();
auto retval = ::mpfr_cmp_si_2exp(x.get_mpfr_t(), n, e);
if (mppp_unlikely(::mpfr_erangeflag_p())) {
::mpfr_clear_erangeflag();
throw std::domain_error("Cannot compare a real NaN to an integral multiple of a power of 2");
}
return retval;
}

// Equality predicate with special NaN handling.
bool real_equal_to(const real &a, const real &b)
{
Expand Down
Loading

0 comments on commit eefa801

Please sign in to comment.