Multiprecision rationals#
Added in version 0.3.
#include <mp++/rational.hpp>
The rational class#
-
template<std::size_t SSize>
class mppp::rational# Multiprecision rational class.
This class represents arbitrary-precision rationals. Internally, the class stores a pair of
integers
with static sizeSSize
as the numerator and denominator. Rational numbers are represented in the usual canonical form:numerator and denominator are coprime,
the denominator is always strictly positive.
Most of the functionality is exposed via plain functions, with the general convention that the functions are named after the corresponding GMP functions minus the leading
mpq_
prefix. For instance, the GMP callmpq_add(rop,a,b);
that writes the result of
a + b
intorop
becomes simplyadd(rop,a,b);
where the
add()
function is resolved via argument-dependent lookup. Function calls with overlapping arguments are allowed, unless noted otherwise.Various overloaded operators are provided.
The
rational
class allows to access and manipulate directly the numerator and denominator via theget_num()
,get_den()
,_get_num()
and_get_den()
member functions, so that it is possible to useinteger
functions directly on numerator and denominator. The mutable getters’ names_get_num()
and_get_den()
are prefixed with an underscore_
to highlight their potentially dangerous nature: it is the user’s responsibility to ensure that the canonical form of the rational is preserved after altering the numerator and/or the denominator via the mutable getters.A tutorial showcasing various features of
rational
is available.-
using int_t = integer<SSize>#
Underlying integral type.
This is the
integer
type used for the representation of numerator and denominator.
-
rational()#
The default constructor initialises to zero.
-
rational(rational &&other) noexcept#
Copy and move constructors.
The copy constructor will perform a copy of numerator and denominator. The move constructor will leave other in an unspecified but valid state.
- Parameters:
other – the construction argument.
-
template<rational_cvr_interoperable<SSize> T>
explicit rational(T &&x)# Generic constructor.
Note
This constructor is not
explicit
ifT
satisfiesrational_integral_interoperable
.This constructor will initialize a rational with the value x. The construction will fail if either:
x is a non-finite floating-point value, or,
x is a complex value whose imaginary part is not zero or whose real part is not finite.
- Parameters:
x – the value that will be used to initialize
this
.- Throws:
std::domain_error – if x is a non-finite floating-point value, or a complex value with non-zero imaginary part or non-finite real part.
-
template<rational_cvr_integral_interoperable<SSize> T, rational_cvr_integral_interoperable<SSize> U>
explicit rational(T &&n, U &&d, bool make_canonical = true)# Constructor from numerator and denominator.
The input value n will be used to initialise the numerator, while d will be used to initialise the denominator. If make_canonical is
true
(the default), thencanonicalise()
will be called after the construction of numerator and denominator.Warning
If this constructor is called with make_canonical set to
false
, it will be the user’s responsibility to ensure thatthis
is canonicalised before using it with other mp++ functions. Failure to do so will result in undefined behaviour.- Parameters:
n – the numerator.
d – the denominator.
make_canonical – if
true
, the rational will be canonicalised after the construction of numerator and denominator.
- Throws:
zero_division_error – if the denominator is zero.
-
template<string_type T>
explicit rational(const T &s, int base = 10)# Constructor from string.
This constructor will initialize
this
from thestring_type
s, which must represent a rational value in base base. The expected format is either a numerator-denominator pair separated by the division operator/
, or just a numerator (in which case the denominator will be set to one). The format for numerator and denominator is described in the documentation of the constructor from string ofinteger
.- Parameters:
s – the input string.
base – the base used in the string representation.
- Throws:
zero_division_error – if the denominator is zero.
unspecified – any exception thrown by the string constructor of
integer
, or by memory errors in standard containers.
-
explicit rational(const char *begin, const char *end, int base = 10)#
Constructor from a range of characters.
This constructor will initialise
this
from the content of the input half-open range, which is interpreted as the string representation of a rational in base base.Internally, the constructor will copy the content of the range to a local buffer, add a string terminator, and invoke the constructor from string.
- Parameters:
begin – the begin of the input range.
end – the end of the input range.
base – the base used in the string representation.
- Throws:
unspecified – any exception thrown by the constructor from string, or by memory errors in standard containers.
-
explicit rational(const mpz_t n)#
Constructor from a GMP integer.
This constructor will initialise the numerator of
this
with a copy of the input GMP integer n, and the denominator to 1.Warning
It is the user’s responsibility to ensure that n has been correctly initialized. Calling this constructor with an uninitialized n results in undefined behaviour.
- Parameters:
n – the input GMP integer.
-
explicit rational(const mpq_t q)#
Constructor from a GMP rational.
This constructor will initialise the numerator and denominator of
this
with copies of those of the GMP rational q.Warning
It is the user’s responsibility to ensure that q has been correctly initialized. Calling this constructor with an uninitialized q results in undefined behaviour.
This constructor will not canonicalise
this
: numerator and denominator are constructed as-is from q.- Parameters:
q – the input GMP rational.
-
explicit rational(mpq_t &&q)#
Move constructor from a GMP rational.
This constructor will move the numerator and denominator of the GMP rational q into
this
.Warning
It is the user’s responsibility to ensure that q has been correctly initialized. Calling this constructor with an uninitialized q results in undefined behaviour.
This constructor will not canonicalise
this
: numerator and denominator are constructed as-is from q.The user must ensure that, after construction,
mpq_clear()
is never called on q: the resources previously owned by q are now owned bythis
, which will take care of releasing them when the destructor is called.Note
Due to a compiler bug, this constructor is not available on Microsoft Visual Studio.
- Parameters:
q – the input GMP rational.
-
rational &operator=(rational &&other) noexcept#
Copy and move assignment.
After move-assignment, other is left in an unspecified but valid state.
- Parameters:
other – the assignment argument.
- Returns:
a reference to
this
.
-
template<rational_cvr_interoperable<SSize> T>
rational &operator=(T &&x)# Generic assignment operator.
This operator will assign x to
this
.- Parameters:
x – the assignment argument.
- Returns:
a reference to
this
.- Throws:
unspecified – any exception thrown by the generic constructor.
-
rational &operator=(const complex128 &x)#
-
rational &operator=(const complex &x)#
Note
The
real128
andcomplex128
overloads are available only if mp++ was configured with theMPPP_WITH_QUADMATH
option enabled. Thereal
overload is available only if mp++ was configured with theMPPP_WITH_MPFR
option enabled. Thecomplex
overload is available only if mp++ was configured with theMPPP_WITH_MPC
option enabled.Added in version 0.20.
Assignment operators from other mp++ classes.
These operators are formally equivalent to converting x to
rational
and then move-assigning the result tothis
.- Parameters:
x – the assignment argument.
- Returns:
a reference to
this
.- Throws:
unspecified – any exception raised by the conversion of x to
rational
.
-
template<string_type T>
rational &operator=(const T &s)# Assignment from string.
The body of this operator is equivalent to:
return *this = rational{s};
That is, a temporary rational is constructed from s and it is then move-assigned to
this
.- Parameters:
s – the string that will be used for the assignment.
- Returns:
a reference to
this
.- Throws:
unspecified – any exception thrown by the constructor from string.
-
rational &operator=(const mpz_t n)#
Assignment from a GMP integer.
This assignment operator will copy into the numerator of
this
the value of the GMP integer n, and it will set the denominator to 1 viamppp::integer::set_one()
.Warning
It is the user’s responsibility to ensure that n has been correctly initialized. Calling this operator with an uninitialized n results in undefined behaviour.
No aliasing is allowed: the data in n must be completely distinct from the data in
this
.- Parameters:
n – the input GMP integer.
- Returns:
a reference to
this
.
-
rational &operator=(const ::mpq_t q)#
Assignment from a GMP rational.
This assignment operator will copy into
this
the value of the GMP rational q.Warning
It is the user’s responsibility to ensure that q has been correctly initialized. Calling this operator with an uninitialized q results in undefined behaviour.
This operator will not canonicalise the assigned value: numerator and denominator are assigned as-is from q.
No aliasing is allowed: the data in q must be completely distinct from the data in
this
.- Parameters:
q – the input GMP rational.
- Returns:
a reference to
this
.
-
rational &operator=(mpq_t &&q)#
Move assignment from a GMP rational.
This assignment operator will move the GMP rational q into
this
.Warning
It is the user’s responsibility to ensure that q has been correctly initialized. Calling this operator with an uninitialized q results in undefined behaviour.
This operator will not canonicalise the assigned value: numerator and denominator are assigned as-is from q.
No aliasing is allowed: the data in q must be completely distinct from the data in
this
.The user must ensure that, after the assignment,
mpq_clear()
is never called on q: the resources previously owned by q are now owned bythis
, which will take care of releasing them when the destructor is called.Note
Due to a compiler bug, this operator is not available on Microsoft Visual Studio.
- Parameters:
q – the input GMP rational.
- Returns:
a reference to
this
.
-
std::string to_string(int base = 10) const#
Convert to string.
This operator will return a string representation of
this
in base base. The string format consists of the numerator, followed by the division operator/
and the denominator, but only if the denominator is not unitary. Otherwise, only the numerator will be represented in the returned string.- Parameters:
base – the desired base for the string representation.
- Returns:
a string representation for
this
.- Throws:
unspecified – any exception thrown by
mppp::integer::to_string()
.
-
template<rational_interoperable<SSize> T>
explicit operator T() const# Generic conversion operator.
This operator will convert
this
toT
. Conversion tobool
yieldsfalse
ifthis
is zero,true
otherwise. Conversion to other integral types and toint_t
yields the result of the truncated division of the numerator by the denominator, if representable by the target type. Conversion to floating-point and complex types might yield inexact values and infinities.- Returns:
this
converted to the target type.- Throws:
std::overflow_error – if the target type is an integral type and the value of
this
overflows its range.
-
template<rational_interoperable<SSize> T>
bool get(T &rop) const# Generic conversion member function.
This member function, similarly to the conversion operator, will convert
this
toT
, storing the result of the conversion into rop. Differently from the conversion operator, this member function does not raise any exception: if the conversion is successful, the member function will returntrue
, otherwise the member function will returnfalse
. If the conversion fails, rop will not be altered.- Parameters:
rop – the variable which will store the result of the conversion.
- Returns:
true
if the conversion succeeded,false
otherwise. The conversion can fail only ifT
is an integral C++ type which cannot represent the truncated value ofthis
.
-
int_t &_get_den()#
Getters for numerator and denominator.
Warning
It is the user’s responsibility to ensure that, after changing the numerator or denominator via one of the mutable getters, the rational is kept in canonical form.
- Returns:
a (const) reference to the numerator or denominator.
-
rational &canonicalise()#
Canonicalise.
This member function will put
this
in canonical form. In particular, this member function will make sure that:the numerator and denominator are coprime (dividing them by their GCD, if necessary),
the denominator is strictly positive.
In general, it is not necessary to call explicitly this member function, as the public API of
rational
ensures that rationals are kept in canonical form. Calling this member function, however, might be necessary if the numerator and/or denominator are modified manually, or when constructing/assigning from non-canonicalmpq_t
values.- Returns:
a reference to
this
.
-
bool is_canonical() const#
Check canonical form.
- Returns:
true
ifthis
is the canonical form for rational numbers,false
otherwise.
-
int sgn() const#
Sign function.
- Returns:
0 if
this
is zero, 1 ifthis
is positive, -1 ifthis
is negation.
-
rational &neg()#
Negate in-place.
This function will set
this
to its negative.- Returns:
a reference to
this
.
-
rational &abs()#
In-place absolute value.
This function will set
this
to its absolute value.- Returns:
a reference to
this
.
-
rational &inv()#
Invert in-place.
This function will set
this
to its inverse.- Returns:
a reference to
this
.- Throws:
zero_division_error – if
this
is zero.
-
bool is_zero() const#
-
bool is_one() const#
-
bool is_negative_one() const#
Test for special values.
- Returns:
true
ifthis
is, respectively, \(0\), \(1\) or \(-1\),false
otherwise.
Types#
-
type mpq_t#
This is the type used by the GMP library to represent multiprecision rationals. It is defined as an array of size 1 of an unspecified structure.
Concepts#
-
template<typename T, std::size_t SSize>
concept mppp::rational_interoperable# This concept is satisfied if the type
T
can interoperate with arational
with static sizeSSize
. Specifically, this concept will betrue
ifT
satisfiesinteger_cpp_arithmetic
orinteger_cpp_complex
, or it is aninteger
with static sizeSSize
.
-
template<typename T, std::size_t SSize>
concept mppp::rational_cvr_interoperable# This concept is satisfied if the type
T
, after the removal of reference and cv qualifiers, satisfiesrational_interoperable
.
-
template<typename T, std::size_t SSize>
concept mppp::rational_integral_interoperable# This concept is satisfied if either:
T
satisfiescpp_integral
, orT
is aninteger
with static sizeSSize
.
-
template<typename T, std::size_t SSize>
concept mppp::rational_cvr_integral_interoperable# This concept is satisfied if the type
T
, after the removal of reference and cv qualifiers, satisfiesrational_integral_interoperable
.
-
template<typename T, typename U>
concept mppp::rational_op_types# This concept is satisfied if the types
T
andU
are suitable for use in the generic binary operators and functions involvingrational
. Specifically, the concept will betrue
if either:T
andU
are bothrational
with the same static sizeSSize
, orone type is a
rational
and the other is arational_interoperable
type.
-
template<typename T, typename U>
concept mppp::rational_real_op_types# This concept will be
true
if:T
andU
satisfyrational_op_types
, andneither
T
norU
satisfyinteger_cpp_complex
.
Functions#
Much of the functionality of the rational
class is exposed
via plain functions. These functions
mimic the GMP API where appropriate, but a variety of
convenience/generic overloads is provided as well.
Assignment#
Conversion#
-
template<std::size_t SSize, mppp::rational_interoperable<SSize> T>
bool mppp::get(T &rop, const mppp::rational<SSize> &q)# Generic conversion function.
This function will convert the input
rational
q to arational_interoperable
type, storing the result of the conversion into rop. If the conversion is successful, the function will returntrue
, otherwise the function will returnfalse
. If the conversion fails, rop will not be altered.- Parameters:
rop – the variable which will store the result of the conversion.
q – the input argument.
- Returns:
true
if the conversion succeeded,false
otherwise. The conversion can fail only ifT
is an integral C++ type which cannot represent the truncated value of q.
Arithmetic#
-
template<std::size_t SSize>
mppp::rational<SSize> &mppp::add(mppp::rational<SSize> &rop, const mppp::rational<SSize> &x, const mppp::rational<SSize> &y)#
-
template<std::size_t SSize>
mppp::rational<SSize> &mppp::sub(mppp::rational<SSize> &rop, const mppp::rational<SSize> &x, const mppp::rational<SSize> &y)#
-
template<std::size_t SSize>
mppp::rational<SSize> &mppp::mul(mppp::rational<SSize> &rop, const mppp::rational<SSize> &x, const mppp::rational<SSize> &y)#
-
template<std::size_t SSize>
mppp::rational<SSize> &mppp::div(mppp::rational<SSize> &rop, const mppp::rational<SSize> &x, const mppp::rational<SSize> &y)# Ternary arithmetic primitives.
These functions will set rop to, respectively:
\(x + y\),
\(x - y\),
\(x \times y\),
\(\frac{x}{y}\).
- Parameters:
rop – the return value.
x – the first operand.
y – the second operand.
- Returns:
a reference to rop.
- Throws:
mppp::zero_division_error – if, in a division operation, y is zero.
-
template<std::size_t SSize>
mppp::rational<SSize> &mppp::neg(mppp::rational<SSize> &rop, const mppp::rational<SSize> &x)#
-
template<std::size_t SSize>
mppp::rational<SSize> &mppp::abs(mppp::rational<SSize> &rop, const mppp::rational<SSize> &x)# Binary negation and absolute value.
These functions will set rop to, respectively, \(-x\) and \(\left| x \right|\).
- Parameters:
rop – the return value.
x – the input value.
- Returns:
a reference to rop.
-
template<std::size_t SSize>
mppp::rational<SSize> mppp::abs(const mppp::rational<SSize> &x)# Unary negation and absolute value.
- Parameters:
x – the input value.
- Returns:
\(-x\) and \(\left| x \right|\) respectively.
-
template<std::size_t SSize>
mppp::rational<SSize> &mppp::inv(mppp::rational<SSize> &rop, const mppp::rational<SSize> &x)# Binary inversion.
This function will set rop to \(x^{-1}\).
- Parameters:
rop – the return value.
x – the input value.
- Returns:
a reference to rop.
- Throws:
unspecified – any exception thrown by
mppp::rational::inv()
.
Comparison#
-
template<std::size_t SSize>
int mppp::cmp(const mppp::rational<SSize> &x, const mppp::rational<SSize> &y)#
-
template<std::size_t SSize>
int mppp::cmp(const mppp::rational<SSize> &x, const mppp::integer<SSize> &y)#
-
template<std::size_t SSize>
int mppp::cmp(const mppp::integer<SSize> &x, const mppp::rational<SSize> &y)# Three-way comparisons.
These functions will return 0 if \(x=y\), a negative value if \(x<y\) and a positive value if \(x>y\).
- Parameters:
x – the first operand.
y – the second operand.
- Returns:
the result of the comparison.
Number theoretic functions#
Added in version 0.8.
-
template<std::size_t SSize, mppp::rational_integral_interoperable<SSize> T>
mppp::rational<SSize> mppp::binomial(const mppp::rational<SSize> &x, const T &y)# Binomial coefficient.
This function will compute the binomial coefficient \({x \choose y}\). If x represents an integral value, the calculation is forwarded to the implementation of the binomial coefficient for
integer
. Otherwise, an implementation based on the falling factorial is employed.- Parameters:
x – the top value.
y – the bottom value.
- Returns:
\({x \choose y}\).
- Throws:
unspecified – any exception thrown by the implementation of the binomial coefficient for
integer
.
Exponentiation#
-
template<typename T, mppp::rational_op_types<T> U>
auto mppp::pow(const T &x, const U &y)# Exponentiation.
This function will return \(x^y\). If one of the arguments is a floating-point or complex value, then the result will be computed via
std::pow()
and it will also be a floating-point or complex value. Otherwise, the result will be arational
.When floating-point and complex types are not involved, the implementation is based on the integral exponentiation of numerator and denominator. Thus, if y is a rational value, the exponentiation will be successful only in a few special cases (e.g., unitary base, zero exponent, etc.).
- Parameters:
x – the base.
y – the exponent.
- Returns:
\(x^y\).
- Throws:
mppp::zero_division_error – if floating-point or complex types are not involved, and x is zero and y negative.
std::domain_error – if floating-point or complex types are not involved and y is a rational value (except in a handful of special cases).
Input/Output#
-
template<std::size_t SSize>
std::ostream &mppp::operator<<(std::ostream &os, const mppp::rational<SSize> &q)# Stream insertion operator.
This function will direct to the output stream os the input
rational
q.- Parameters:
os – the output stream.
q – the input
rational
.
- Returns:
a reference to os.
- Throws:
std::overflow_error – in case of (unlikely) overflow errors.
unspecified – any exception raised by the public interface of
std::ostream
or by memory allocation errors.
Other#
-
template<std::size_t SSize>
mppp::rational<SSize> &mppp::canonicalise(mppp::rational<SSize> &rop)# Canonicalise.
This function will put rop in canonical form. Internally, this function will employ
mppp::rational::canonicalise()
.- Parameters:
rop – the rational that will be canonicalised.
- Returns:
a reference to rop.
-
template<std::size_t SSize>
std::size_t mppp::hash(const mppp::rational<SSize> &q)# Hash value.
This function will return a hash value for q.
A specialisation of the standard
std::hash
functor is also provided, so that it is possible to userational
in standard unordered associative containers out of the box.- Parameters:
q – the rational whose hash value will be computed.
- Returns:
a hash value for q.
Mathematical operators#
Overloaded operators are provided for convenience. Their interface is generic, and their implementation is typically built on top of basic functions.
-
template<std::size_t SSize>
mppp::rational<SSize> mppp::operator-(const mppp::rational<SSize> &q)# Identity and negation operators.
- Parameters:
q – the input value.
- Returns:
\(q\) and \(-q\) respectively.
-
template<typename T, mppp::rational_op_types<T> U>
auto mppp::operator+(const T &x, const U &y)#
-
template<typename T, mppp::rational_op_types<T> U>
auto mppp::operator-(const T &x, const U &y)#
-
template<typename T, mppp::rational_op_types<T> U>
auto mppp::operator*(const T &x, const U &y)#
-
template<typename T, mppp::rational_op_types<T> U>
auto mppp::operator/(const T &x, const U &y)# Binary arithmetic operators.
These operators will return, respectively:
\(x+y\),
\(x-y\),
\(x \times y\),
\(\frac{x}{y}\).
The return type of these operators is determined as follows:
if the non-
rational
argument is a floating-point or complex value, then the type of the result is floating-point or complex; otherwise,the type of the result is
rational
.
- Parameters:
x – the first operand.
y – the second operand.
- Returns:
the result of the operation.
- Throws:
mppp::zero_division_error – if, in a division not involving floating-point or complex values, y is zero.
-
template<typename T, mppp::rational_op_types<T> U>
auto mppp::operator+=(T &x, const U &y)#
-
template<typename T, mppp::rational_op_types<T> U>
auto mppp::operator-=(T &x, const U &y)#
-
template<typename T, mppp::rational_op_types<T> U>
auto mppp::operator*=(T &x, const U &y)#
-
template<typename T, mppp::rational_op_types<T> U>
auto mppp::operator/=(T &x, const U &y)# In-place arithmetic operators.
These operators will set x to, respectively:
\(x+y\),
\(x-y\),
\(x \times y\),
\(\frac{x}{y}\).
- Parameters:
x – the first operand.
y – the second operand.
- Returns:
a reference to x.
- Throws:
mppp::zero_division_error – if, in a division not involving floating-point or complex values, y is zero.
unspecified – any exception thrown by the assignment/conversion operators of
rational
.
-
template<std::size_t SSize>
mppp::rational<SSize> &mppp::operator--(mppp::rational<SSize> &q)# Prefix increment/decrement.
- Parameters:
q – the input argument.
- Returns:
a reference to q after the increment/decrement.
-
template<std::size_t SSize>
mppp::rational<SSize> mppp::operator--(mppp::rational<SSize> &q, int)# Suffix increment/decrement.
- Parameters:
q – the input argument.
- Returns:
a copy of q before the increment/decrement.
-
template<typename T, mppp::rational_op_types<T> U>
bool mppp::operator==(const T &op1, const U &op2)#
-
template<typename T, mppp::rational_op_types<T> U>
bool mppp::operator!=(const T &op1, const U &op2)#
-
template<typename T, mppp::rational_op_types<T> U>
bool mppp::operator<(const T &op1, const U &op2)#
-
template<typename T, mppp::rational_op_types<T> U>
bool mppp::operator<=(const T &op1, const U &op2)#
-
template<typename T, mppp::rational_op_types<T> U>
bool mppp::operator>(const T &op1, const U &op2)#
-
template<typename T, mppp::rational_op_types<T> U>
bool mppp::operator>=(const T &op1, const U &op2)# Binary comparison operators.
- Parameters:
op1 – first argument.
op2 – second argument.
- Returns:
the result of the comparison.
Standard library specialisations#
-
template<std::size_t SSize>
class std::hash<mppp::rational<SSize>># Specialisation of
std::hash
formppp::rational
.-
using result_type = std::size_t#
Note
The
argument_type
andresult_type
type aliases are defined only until C++14.-
std::size_t operator()(const mppp::rational<SSize> &q) const#
- Parameters:
q – the input
mppp::rational
.- Returns:
a hash value for q.
-
using result_type = std::size_t#
User-defined literals#
Added in version 0.19.
-
template<char... Chars>
mppp::rational<3> mppp::literals::operator""_q3()# User-defined rational literals.
These numeric literal operator templates can be used to construct
rational
instances with, respectively, 1, 2 and 3 limbs of static storage. Literals in binary, octal, decimal and hexadecimal format are supported.Note that only integral values (i.e., rationals with unitary denominator) can be constructed via these literals.
- Throws:
std::invalid_argument – if the input sequence of characters is not a valid integer literal (as defined by the C++ standard).