Skip to content
Open
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
12 changes: 8 additions & 4 deletions doc/reference_number.qbk
Original file line number Diff line number Diff line change
Expand Up @@ -262,8 +262,8 @@
bool miller_rabin_test(const ``['number-or-expression-template-type]``& n, unsigned trials);

// Rational number support:
typename component_type<``['number-or-expression-template-type]``>::type numerator (const ``['number-or-expression-template-type]``&);
typename component_type<``['number-or-expression-template-type]``>::type denominator(const ``['number-or-expression-template-type]``&);
typename component_type<``['number-or-expression-template-type]``>::type const& numerator (const ``['number-or-expression-template-type]``&);
typename component_type<``['number-or-expression-template-type]``>::type const& denominator(const ``['number-or-expression-template-type]``&);

}} // namespaces

Expand Down Expand Up @@ -817,11 +817,15 @@ to ensure accuracy.

[h4 Rational Number Functions]

typename component_type<``['number-or-expression-template-type]``>::type numerator (const ``['number-or-expression-template-type]``&);
typename component_type<``['number-or-expression-template-type]``>::type denominator(const ``['number-or-expression-template-type]``&);
typename component_type<``['number-or-expression-template-type]``>::type const& numerator (const ``['number-or-expression-template-type]``&);
typename component_type<``['number-or-expression-template-type]``>::type const& denominator(const ``['number-or-expression-template-type]``&);

These functions return the numerator and denominator of a rational number respectively.

The returned value is by reference wherever possible. However, there are a few types, most notably where the number uses
`logged_adaptor` or `debug_adaptor` where this is not possible and the result is a temporary returned by value. As a result
code should *never* rely on a reference being returned.

[h4 Boost.Math Interoperability Support]

namespace boost{ namespace math{
Expand Down
41 changes: 4 additions & 37 deletions doc/tutorial_boost_rational.qbk
Original file line number Diff line number Diff line change
Expand Up @@ -8,43 +8,10 @@
http://www.boost.org/LICENSE_1_0.txt).
]

[section:tommath_rational tommath_rational]
[section:br Use With Boost.Rational]

`#include <boost/multiprecision/tommath.hpp>`
All of the integer types in this library can be used as template arguments to `boost::rational<IntType>`.

namespace boost{ namespace multiprecision{
Note that using the library in this way largely negates the effect of the expression templates in `number`.

typedef rational_adpater<tommath_int> tommath_rational;
typedef number<tommath_rational > tom_rational;

}} // namespaces

The `tommath_rational` back-end is used via the typedef `boost::multiprecision::tom_rational`. It acts as a thin wrapper around
`boost::rational<tom_int>`
to provide a rational number type that is a drop-in replacement for the native C++ number types, but with unlimited precision.

The advantage of using this type rather than `boost::rational<tom_int>` directly, is that it is expression-template enabled,
greatly reducing the number of temporaries created in complex expressions.

There are also non-member functions:

tom_int numerator(const tom_rational&);
tom_int denominator(const tom_rational&);

which return the numerator and denominator of the number.

Things you should know when using this type:

* Default constructed `tom_rational`s have the value zero (this the inherited Boost.Rational behavior).
* Division by zero results in a `std::overflow_error` being thrown.
* Conversion from a string results in a `std::runtime_error` being thrown if the string can not be
interpreted as a valid rational number.
* No changes are made to [tommath]'s global state, so this type can safely coexist with other [tommath] code.
* Performance of this type has been found to be pretty poor - this need further investigation - but it appears that Boost.Rational
needs some improvement in this area.

[h5 Example:]

[mp_rat_eg]

[endsect] [/section:tommath_rational tommath_rational]
[endsect] [/section:br Use With Boost.Rational]
4 changes: 2 additions & 2 deletions doc/tutorial_cpp_rational.qbk
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ There is also a two argument constructor that accepts a numerator and denominato

There are also non-member functions:

cpp_int numerator(const cpp_rational&);
cpp_int denominator(const cpp_rational&);
cpp_int const& numerator(const cpp_rational&);
cpp_int const& denominator(const cpp_rational&);

which return the numerator and denominator of the number.

Expand Down
4 changes: 2 additions & 2 deletions doc/tutorial_gmp_rational.qbk
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@ There is also a two-argument constructor that accepts a numerator and denominato

There are also non-member functions:

mpz_int numerator(const mpq_rational&);
mpz_int denominator(const mpq_rational&);
mpz_int const& numerator(const mpq_rational&);
mpz_int const& denominator(const mpq_rational&);

which return the numerator and denominator of the number.

Expand Down
2 changes: 1 addition & 1 deletion doc/tutorial_rational_adaptor.qbk
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

namespace boost{ namespace multiprecision{

template <class IntBackend>
template <class IntBackend, expression_template_option ExpressionTemplates = expression_template_default<Backend>::value>
class rational_adpater;

}}
Expand Down
4 changes: 2 additions & 2 deletions doc/tutorial_tommath_rational.qbk
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ greatly reducing the number of temporaries created in complex expressions.

There are also non-member functions:

tom_int numerator(const tom_rational&);
tom_int denominator(const tom_rational&);
tom_int const& numerator(const tom_rational&);
tom_int const& denominator(const tom_rational&);

which return the numerator and denominator of the number.

Expand Down
2 changes: 1 addition & 1 deletion include/boost/multiprecision/fwd.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ namespace boost {
template <>
struct mpfr_float_backend<0, allocate_stack>;

template <class Backend>
template <class Backend, expression_template_option ExpressionTemplates = expression_template_default<Backend>::value>
struct rational_adaptor;

struct tommath_int;
Expand Down
21 changes: 18 additions & 3 deletions include/boost/multiprecision/gmp.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3270,20 +3270,35 @@ struct component_type<number<gmp_rational, ExpressionTemplates> >
{
using type = number<gmp_int, ExpressionTemplates>;
};

//
// The following code breaks C++'s strict aliasing rules, but works
// because we are casting between (references to) two layout-compatible types.
// We do this for performance reasons to avoid making an unnecessary copy
// (which involves two expensive memory allocations).
// If this causes issues down the road, then we will revert to the old
// return-by-value approach.
//
template <expression_template_option ET>
inline number<gmp_int, ET> numerator(const number<gmp_rational, ET>& val)
inline const number<gmp_int, ET>& numerator(const number<gmp_rational, ET>& val)
{
#if 0
number<gmp_int, ET> result;
mpz_set(result.backend().data(), (mpq_numref(val.backend().data())));
return result;
#endif
static_assert(sizeof(number<gmp_int, ET>) == sizeof(*mpq_numref(val.backend().data())), "Size sanity check failed");
return reinterpret_cast<const number<gmp_int, ET>&>(*mpq_numref(val.backend().data()));
}
template <expression_template_option ET>
inline number<gmp_int, ET> denominator(const number<gmp_rational, ET>& val)
inline const number<gmp_int, ET>& denominator(const number<gmp_rational, ET>& val)
{
#if 0
number<gmp_int, ET> result;
mpz_set(result.backend().data(), (mpq_denref(val.backend().data())));
return result;
#endif
static_assert(sizeof(number<gmp_int, ET>) == sizeof(*mpq_numref(val.backend().data())), "Size sanity check failed");
return reinterpret_cast<const number<gmp_int, ET>&>(*mpq_denref(val.backend().data()));
}

namespace detail {
Expand Down
Loading