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