diff --git a/mapytex/calculus/core/MO/fraction.py b/mapytex/calculus/core/MO/fraction.py index fe42a7f..59fdaba 100644 --- a/mapytex/calculus/core/MO/fraction.py +++ b/mapytex/calculus/core/MO/fraction.py @@ -46,6 +46,24 @@ class MOFraction(MO): self._denominator = denominator self.negative = negative + @property + def numerator(self): + """ Get the numerator. If self is negative, getting the opposite of the _numerator + """ + if self.negative: + return Tree("-", None, self._numerator) + + return self._numerator + + @property + def denominator(self): + return self._denominator + + def inverse(self): + """ return the inverse fraction """ + return MOFraction(self._denominator, + self._numerator, + self.negative) # ----------------------------- # Reglages pour 'vim' diff --git a/mapytex/calculus/core/compute/add.py b/mapytex/calculus/core/compute/add.py index dd9ffe0..84c6e0e 100644 --- a/mapytex/calculus/core/compute/add.py +++ b/mapytex/calculus/core/compute/add.py @@ -15,6 +15,7 @@ from ..operator import OPERATORS from ..MO.mo import MO, MOnumber, MOstr from ..MO.fraction import MOFraction from .exceptions import AddError +from .arithmetic import lcm def add(left, right): @@ -106,11 +107,109 @@ def mofraction_monumber(left, right): right_fraction = MOFraction(right, MOnumber(1)) return Tree("+", left, right_fraction) +def mofraction_mofraction(left, right): + """ Adding two mofractions + + :param left: a mofraction + :param right: a mofraction + :returns: Tree + + >>> a = MOFraction(1, 5) + >>> b = MOFraction(4, 5) + >>> print(mofraction_mofraction(a, b)) + / + > + + | > 1 + | > 4 + > 5 + >>> a = MOFraction(1, 5, True) + >>> b = MOFraction(4, 5) + >>> print(mofraction_mofraction(a, b)) + / + > + + | > - + | | > None + | | > 1 + | > 4 + > 5 + >>> a = MOFraction(1, 5) + >>> b = MOFraction(4, 5, True) + >>> print(mofraction_mofraction(a, b)) + / + > + + | > 1 + | > - + | | > None + | | > 4 + > 5 + >>> a = MOFraction(1, 2) + >>> b = MOFraction(1, 4) + >>> print(mofraction_mofraction(a, b)) + + + > / + | > * + | | > 1 + | | > 2 + | > * + | | > 2 + | | > 2 + > / + | > 1 + | > 4 + >>> a = MOFraction(1, 2) + >>> b = MOFraction(1, 5) + >>> print(mofraction_mofraction(a, b)) + + + > / + | > * + | | > 1 + | | > 5 + | > * + | | > 2 + | | > 5 + > / + | > * + | | > 1 + | | > 2 + | > * + | | > 5 + | | > 2 + """ + + if not isinstance(left, MOFraction) or not isinstance(right, MOFraction): + raise AddError(f"Wrong type for left (got {left.__class__.__name__})" + f"or right (got {right.__class__.__name__})") + + if left.denominator == right.denominator: + num = Tree("+", left.numerator, right.numerator) + return Tree("/", num, left.denominator) + + denom_lcm = lcm(left.denominator, right.denominator) + + if left.denominator == denom_lcm: + left_frac = left + else: + multiply_by = denom_lcm // left.denominator + left_num = Tree("*", left.numerator, MO.factory(multiply_by)) + left_denom = Tree("*", left.denominator, MO.factory(multiply_by)) + left_frac = Tree("/", left_num, left_denom) + + if right.denominator == denom_lcm: + right_frac = right + else: + multiply_by = denom_lcm // right.denominator + right_num = Tree("*", right.numerator, MO.factory(multiply_by)) + right_denom = Tree("*", right.denominator, MO.factory(multiply_by)) + right_frac = Tree("/", right_num, right_denom) + + return Tree("+", left_frac, right_frac) + # TODO: Faire un décorateur pour un enregistrement automatique |dim. mars 11 18:24:32 EAT 2018 ADDFUNCTIONS = { (MOnumber, MOnumber): monumber_monumber, (MOnumber, MOFraction): monumber_mofraction, (MOFraction, MOnumber): mofraction_monumber, + (MOFraction, MOFraction): mofraction_mofraction, } # ----------------------------- diff --git a/mapytex/calculus/core/compute/arithmetic.py b/mapytex/calculus/core/compute/arithmetic.py new file mode 100644 index 0000000..be607f4 --- /dev/null +++ b/mapytex/calculus/core/compute/arithmetic.py @@ -0,0 +1,77 @@ +#!/usr/bin/env python +# encoding: utf-8 + + +__all__ = ['gcd'] + + +def gcd(a, b): + """Compute gcd(a,b) + + :param a: first number (need to support abs, comparison, * and %) + :param b: second number (need to support abs, comparison, * and %) + :returns: the gcd + + >>> gcd(3, 15) + 3 + >>> gcd(15, 3) + 3 + >>> gcd(-3, -15) + -3 + >>> gcd(5, 12) + 1 + >>> gcd(4, 14) + 2 + + """ + pos_a, _a = (a >= 0), abs(a) + pos_b, _b = (b >= 0), abs(b) + + gcd_sgn = (-1 + 2 * (pos_a or pos_b)) + + if _a > _b: + c = _a % _b + else: + c = _b % _a + + if c == 0: + return gcd_sgn * min(_a, _b) + elif _a == 1: + return gcd_sgn * _b + elif _b == 1: + return gcd_sgn * _a + else: + return gcd_sgn * gcd(min(_a, _b), c) + +def lcm(a, b): + """Compute lcm(a,b) + + :param a: first number (need to support abs, comparison, *, % and //) + :param b: second number (need to support abs, comparison, *, % and //) + :returns: the lcm + + >>> lcm(3, 15) + 15 + >>> lcm(15, 3) + 15 + >>> lcm(-3, -15) + -15 + >>> lcm(5, 12) + 60 + >>> lcm(4, 14) + 28 + + """ + return (a * b) // gcd(a, b) + +if __name__ == '__main__': + print(gcd(3, 15)) + print(gcd(3, 15)) + print(gcd(-15, -3)) + print(gcd(-3, -12)) + + +# ----------------------------- +# Reglages pour 'vim' +# vim:set autoindent expandtab tabstop=4 shiftwidth=4: +# cursor: 16 del diff --git a/mapytex/calculus/core/compute/multiply.py b/mapytex/calculus/core/compute/multiply.py index e19e9dd..08c8797 100644 --- a/mapytex/calculus/core/compute/multiply.py +++ b/mapytex/calculus/core/compute/multiply.py @@ -74,25 +74,21 @@ def monumber_mofraction(left, right): > 5 >>> b = MOFraction(6, 5, True) >>> print(monumber_mofraction(a, b)) - - - > None - > / - | > * - | | > 4 + / + > * + | > 4 + | > - + | | > None | | > 6 - | > 5 + > 5 """ if not isinstance(left, MOnumber) or not isinstance(right, MOFraction): raise MultiplyError(f"Wrong type for left (got {left.__class__.__name__}) \ or right (got {right.__class__.__name__})") - num = Tree("*", left, right._numerator) - frac = Tree("/", num, right._denominator) - if right.negative: - return Tree("-", None, frac) - - return frac + num = Tree("*", left, right.numerator) + return Tree("/", num, right._denominator) def mofraction_monumber(left, right): """ Adding a monumber and a mofraction @@ -115,12 +111,8 @@ def mofraction_monumber(left, right): raise MultiplyError(f"Wrong type for left (got {left.__class__.__name__})" f"or right (got {right.__class__.__name__})") - num = Tree("*", left._numerator, right) - frac = Tree("/", num, left._denominator) - if left.negative: - return Tree("-", None, frac) - - return frac + num = Tree("*", left.numerator, right) + return Tree("/", num, left._denominator) # TODO: Faire un décorateur pour un enregistrement automatique |dim. mars 11 18:24:32 EAT 2018 MULFUNCTIONS = {