mirror of
https://github.com/UpsilonNumworks/Upsilon.git
synced 2026-03-28 18:20:14 +01:00
179 lines
5.3 KiB
C++
179 lines
5.3 KiB
C++
#include <poincare/rational.h>
|
|
extern "C" {
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <assert.h>
|
|
#include <math.h>
|
|
}
|
|
#include <poincare/arithmetic.h>
|
|
#include <poincare/opposite.h>
|
|
#include <poincare/fraction_layout_node.h>
|
|
|
|
namespace Poincare {
|
|
|
|
// Constructors
|
|
|
|
Rational::Rational(const Integer numerator, const Integer denominator) {
|
|
assert(!denominator.isZero());
|
|
if (numerator.isOne() || denominator.isOne()) {
|
|
// Avoid computing GCD if possible
|
|
m_numerator = numerator;
|
|
m_denominator = denominator;
|
|
} else {
|
|
Integer gcd = Arithmetic::GCD(&numerator, &denominator);
|
|
m_numerator = Integer::Division(numerator, gcd).quotient;
|
|
m_denominator = Integer::Division(denominator, gcd).quotient;
|
|
}
|
|
if (m_numerator.isNegative() && m_denominator.isNegative()) {
|
|
m_numerator.setNegative(false);
|
|
m_denominator.setNegative(false);
|
|
} else if (m_denominator.isNegative()) {
|
|
m_numerator.setNegative(true);
|
|
m_denominator.setNegative(false);
|
|
}
|
|
}
|
|
|
|
Rational::Rational(const Integer numerator) {
|
|
m_numerator = numerator;
|
|
m_denominator = Integer(1);
|
|
}
|
|
|
|
Rational::Rational(const Rational & other) {
|
|
m_numerator = other.m_numerator;
|
|
m_denominator = other.m_denominator;
|
|
}
|
|
|
|
Rational & Rational::operator=(const Rational & other) {
|
|
m_numerator = other.m_numerator;
|
|
m_numerator = other.m_numerator;
|
|
m_denominator = other.m_denominator;
|
|
return *this;
|
|
}
|
|
|
|
// Getter
|
|
const Integer Rational::numerator() const {
|
|
return m_numerator;
|
|
}
|
|
|
|
const Integer Rational::denominator() const {
|
|
return m_denominator;
|
|
}
|
|
// Expression subclassing
|
|
|
|
Expression::Type Rational::type() const {
|
|
return Type::Rational;
|
|
}
|
|
|
|
Expression * Rational::clone() const {
|
|
return new Rational(m_numerator, m_denominator);
|
|
}
|
|
|
|
Expression::Sign Rational::sign() const {
|
|
if (m_numerator.isNegative()) {
|
|
return Sign::Negative;
|
|
}
|
|
return Sign::Positive;
|
|
}
|
|
|
|
Expression * Rational::setSign(Sign s) {
|
|
assert(s != Sign::Unknown);
|
|
bool negative = s == Sign::Negative ? true : false;
|
|
m_numerator.setNegative(negative);
|
|
return this;
|
|
}
|
|
|
|
Expression * Rational::shallowBeautify(Context & context, Preferences::AngleUnit angleUnit) {
|
|
if (m_numerator.isNegative()) {
|
|
m_numerator.setNegative(false);
|
|
Opposite * o = new Opposite(this, true);
|
|
return replaceWith(o, true);
|
|
}
|
|
return this;
|
|
}
|
|
|
|
Expression * Rational::cloneDenominator(Context & context, Preferences::AngleUnit angleUnit) const {
|
|
if (m_denominator.isOne()) {
|
|
return nullptr;
|
|
}
|
|
return new Rational(m_denominator);
|
|
}
|
|
|
|
// Basic operations
|
|
|
|
Rational Rational::Addition(const Rational & i, const Rational & j) {
|
|
Integer newNumerator = Integer::Addition(Integer::Multiplication(i.numerator(), j.denominator()), Integer::Multiplication(j.numerator(), i.denominator()));
|
|
Integer newDenominator = Integer::Multiplication(i.denominator(), j.denominator());
|
|
return Rational(newNumerator, newDenominator);
|
|
}
|
|
|
|
Rational Rational::Multiplication(const Rational & i, const Rational & j) {
|
|
Integer newNumerator = Integer::Multiplication(i.numerator(), j.numerator());
|
|
Integer newDenominator = Integer::Multiplication(i.denominator(), j.denominator());
|
|
return Rational(newNumerator, newDenominator);
|
|
}
|
|
|
|
Rational Rational::Power(const Rational & i, const Integer & j) {
|
|
Integer absJ = j;
|
|
absJ.setNegative(false);
|
|
Integer newNumerator = Integer::Power(i.numerator(), absJ);
|
|
Integer newDenominator = Integer::Power(i.denominator(), absJ);
|
|
if (j.isNegative()) {
|
|
return Rational(newDenominator, newNumerator);
|
|
}
|
|
return Rational(newNumerator, newDenominator);
|
|
}
|
|
|
|
int Rational::NaturalOrder(const Rational & i, const Rational & j) {
|
|
Integer i1 = Integer::Multiplication(i.numerator(), j.denominator());
|
|
Integer i2 = Integer::Multiplication(i.denominator(), j.numerator());
|
|
return Integer::NaturalOrder(i1, i2);
|
|
}
|
|
|
|
// Comparison
|
|
|
|
int Rational::simplificationOrderSameType(const Expression * e, bool canBeInterrupted) const {
|
|
assert(e->type() == Expression::Type::Rational);
|
|
const Rational * other = static_cast<const Rational *>(e);
|
|
return NaturalOrder(*this, *other);
|
|
}
|
|
|
|
template<typename T> Complex<T> * Rational::templatedApproximate(Context& context, Preferences::AngleUnit angleUnit) const {
|
|
T n = m_numerator.approximate<T>();
|
|
T d = m_denominator.approximate<T>();
|
|
return new Complex<T>(n/d);
|
|
}
|
|
|
|
bool Rational::needParenthesisWithParent(const Expression * e) const {
|
|
if (m_denominator.isOne()) {
|
|
return false;
|
|
}
|
|
Type types[] = {Type::Division, Type::Power, Type::Factorial};
|
|
return e->isOfType(types, 3);
|
|
}
|
|
|
|
LayoutRef Rational::createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const {
|
|
LayoutRef numeratorLayout = m_numerator.createLayout();
|
|
if (m_denominator.isOne()) {
|
|
return numeratorLayout;
|
|
}
|
|
LayoutRef denominatorLayout = m_denominator.createLayout();
|
|
return FractionLayoutRef(numeratorLayout, denominatorLayout);
|
|
}
|
|
|
|
int Rational::writeTextInBuffer(char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const {
|
|
buffer[bufferSize-1] = 0;
|
|
int numberOfChar = m_numerator.writeTextInBuffer(buffer, bufferSize);
|
|
if (m_denominator.isOne()) {
|
|
return numberOfChar;
|
|
}
|
|
if (numberOfChar >= bufferSize-1) {
|
|
return numberOfChar;
|
|
}
|
|
buffer[numberOfChar++] = '/';
|
|
numberOfChar += m_denominator.writeTextInBuffer(buffer+numberOfChar, bufferSize-numberOfChar);
|
|
return numberOfChar;
|
|
}
|
|
|
|
}
|
|
|