Program Listing for File rational.h¶
↰ Return to documentation for file (symengine/symengine/rational.h
)
#ifndef SYMENGINE_RATIONAL_H
#define SYMENGINE_RATIONAL_H
#include <symengine/constants.h>
#include <symengine/symengine_exception.h>
namespace SymEngine
{
class Rational : public Number
{
private:
rational_class i;
public:
IMPLEMENT_TYPEID(SYMENGINE_RATIONAL)
Rational(rational_class &&_i) : i(std::move(_i))
{
SYMENGINE_ASSIGN_TYPEID()
}
static RCP<const Number> from_mpq(const rational_class &i);
static RCP<const Number> from_mpq(rational_class &&i);
virtual hash_t __hash__() const;
virtual bool __eq__(const Basic &o) const;
virtual int compare(const Basic &o) const;
bool is_canonical(const rational_class &i) const;
static RCP<const Number> from_two_ints(const Integer &n, const Integer &d);
static RCP<const Number> from_two_ints(const long n, const long d);
inline const rational_class &as_rational_class() const
{
return this->i;
}
virtual bool is_zero() const
{
return this->i == 0;
}
virtual bool is_one() const
{
return this->i == 1;
}
virtual bool is_minus_one() const
{
return this->i == -1;
}
inline bool is_int() const
{
return this->i == 1;
}
inline virtual bool is_positive() const
{
return i > 0;
}
inline virtual bool is_negative() const
{
return i < 0;
}
// False is returned because a rational cannot have an imaginary part
inline virtual bool is_complex() const
{
return false;
}
inline RCP<const Rational> neg() const
{
return make_rcp<const Rational>(-i);
}
virtual bool is_perfect_power(bool is_expected = false) const;
// \return true if there is a exact nth root of self.
virtual bool nth_root(const Ptr<RCP<const Number>> &,
unsigned long n) const;
inline RCP<const Number> addrat(const Rational &other) const
{
return from_mpq(this->i + other.i);
}
inline RCP<const Number> addrat(const Integer &other) const
{
return from_mpq(this->i + other.as_integer_class());
}
inline RCP<const Number> subrat(const Rational &other) const
{
return from_mpq(this->i - other.i);
}
inline RCP<const Number> subrat(const Integer &other) const
{
return from_mpq(this->i - other.as_integer_class());
}
inline RCP<const Number> rsubrat(const Integer &other) const
{
return from_mpq(other.as_integer_class() - this->i);
}
inline RCP<const Number> mulrat(const Rational &other) const
{
return from_mpq(this->i * other.i);
}
inline RCP<const Number> mulrat(const Integer &other) const
{
return from_mpq(this->i * other.as_integer_class());
}
inline RCP<const Number> divrat(const Rational &other) const
{
if (other.i == 0) {
if (this->i == 0) {
return Nan;
} else {
return ComplexInf;
}
} else {
return from_mpq(this->i / other.i);
}
}
inline RCP<const Number> divrat(const Integer &other) const
{
if (other.as_integer_class() == 0) {
if (this->i == 0) {
return Nan;
} else {
return ComplexInf;
}
} else {
return from_mpq(this->i / other.as_integer_class());
}
}
inline RCP<const Number> rdivrat(const Integer &other) const
{
if (this->i == 0) {
if (other.is_zero()) {
return Nan;
} else {
return ComplexInf;
}
} else {
return from_mpq(other.as_integer_class() / this->i);
}
}
inline RCP<const Number> powrat(const Integer &other) const
{
bool neg = other.is_negative();
integer_class exp_ = other.as_integer_class();
if (neg)
exp_ = -exp_;
if (not mp_fits_ulong_p(exp_))
throw SymEngineException("powrat: 'exp' does not fit ulong.");
unsigned long exp = mp_get_ui(exp_);
#if SYMENGINE_INTEGER_CLASS == SYMENGINE_BOOSTMP
// boost::multiprecision::cpp_rational doesn't provide
// non-const references to num and den
integer_class num;
integer_class den;
mp_pow_ui(num, SymEngine::get_num(i), exp);
mp_pow_ui(den, SymEngine::get_den(i), exp);
rational_class val(num, den);
#else
rational_class val;
mp_pow_ui(SymEngine::get_num(val), SymEngine::get_num(i), exp);
mp_pow_ui(SymEngine::get_den(val), SymEngine::get_den(i), exp);
#endif
// Since 'this' is in canonical form, so is this**other, so we simply
// pass val into the constructor directly without canonicalizing:
if (not neg) {
return Rational::from_mpq(std::move(val));
} else {
return Rational::from_mpq(1 / val);
}
}
RCP<const Basic> powrat(const Rational &other) const;
RCP<const Basic> rpowrat(const Integer &other) const;
virtual RCP<const Number> add(const Number &other) const
{
if (is_a<Rational>(other)) {
return addrat(down_cast<const Rational &>(other));
} else if (is_a<Integer>(other)) {
return addrat(down_cast<const Integer &>(other));
} else {
return other.add(*this);
}
};
virtual RCP<const Number> sub(const Number &other) const
{
if (is_a<Rational>(other)) {
return subrat(down_cast<const Rational &>(other));
} else if (is_a<Integer>(other)) {
return subrat(down_cast<const Integer &>(other));
} else {
return other.rsub(*this);
}
};
virtual RCP<const Number> rsub(const Number &other) const
{
if (is_a<Integer>(other)) {
return rsubrat(down_cast<const Integer &>(other));
} else {
throw NotImplementedError("Not Implemented");
}
};
virtual RCP<const Number> mul(const Number &other) const
{
if (is_a<Rational>(other)) {
return mulrat(down_cast<const Rational &>(other));
} else if (is_a<Integer>(other)) {
return mulrat(down_cast<const Integer &>(other));
} else {
return other.mul(*this);
}
};
virtual RCP<const Number> div(const Number &other) const
{
if (is_a<Rational>(other)) {
return divrat(down_cast<const Rational &>(other));
} else if (is_a<Integer>(other)) {
return divrat(down_cast<const Integer &>(other));
} else {
return other.rdiv(*this);
}
};
virtual RCP<const Number> rdiv(const Number &other) const
{
if (is_a<Integer>(other)) {
return rdivrat(down_cast<const Integer &>(other));
} else {
throw NotImplementedError("Not Implemented");
}
};
virtual RCP<const Number> pow(const Number &other) const
{
if (is_a<Integer>(other)) {
return powrat(down_cast<const Integer &>(other));
} else {
return other.rpow(*this);
}
};
virtual RCP<const Number> rpow(const Number &other) const
{
throw NotImplementedError("Not Implemented");
};
RCP<const Integer> get_num() const
{
return integer(SymEngine::get_num(i));
}
RCP<const Integer> get_den() const
{
return integer(SymEngine::get_den(i));
}
};
void get_num_den(const Rational &rat, const Ptr<RCP<const Integer>> &num,
const Ptr<RCP<const Integer>> &den);
inline RCP<const Number> rational(long n, long d)
{
return Rational::from_two_ints(n, d);
}
} // SymEngine
#endif