Merge branch 'calc_fraction_nostr' into calc_fraction
Conflicts: calculus.py fraction.py
This commit is contained in:
commit
f4ea0dcc42
173
calculus.py
173
calculus.py
@ -3,32 +3,51 @@
|
||||
|
||||
|
||||
from generic import Stack
|
||||
from fraction import Fraction
|
||||
|
||||
def str2tokens(exp):
|
||||
"""Convert an expression into a list of tokens
|
||||
|
||||
:param exp: The expression
|
||||
:returns: the list of tokens
|
||||
|
||||
def infixToPostfix(infixExp):
|
||||
"""Transform an infix expression into postfix expression
|
||||
>>> str2tokens("1 + 2")
|
||||
[1, '+', 2]
|
||||
|
||||
:param infixExp: an infix expression (caracters must be separate by a space)
|
||||
:returns: the corresponding postfix expression
|
||||
"""
|
||||
tokens = exp.split(" ")
|
||||
|
||||
for (i,t) in enumerate(tokens):
|
||||
try:
|
||||
tokens[i] = int(t)
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
return tokens
|
||||
|
||||
def infixToPostfix(infixTokens):
|
||||
"""Transform an infix list of tokens into postfix tokens
|
||||
|
||||
:param infixTokens: an infix list of tokens
|
||||
:returns: the corresponding postfix list of tokens
|
||||
|
||||
:Example:
|
||||
|
||||
>>> infixToPostfix("1 + 2")
|
||||
'1 2 +'
|
||||
|
||||
>>> infixToPostfix("1 * 2 + 3")
|
||||
'1 2 * 3 +'
|
||||
>>> infixToPostfix([1, "+", 2])
|
||||
[1, 2, '+']
|
||||
|
||||
>>> infixToPostfix([1, "*", 2, "+", 3])
|
||||
[1, 2, '*', 3, '+']
|
||||
"""
|
||||
|
||||
priority = {"*" : 3, "/": 3, "+": 2, "-":2, "(": 1}
|
||||
|
||||
opStack = Stack()
|
||||
postfixList = []
|
||||
|
||||
tokenList = infixExp.split(" ")
|
||||
#infixTokens = infixExp.split(" ")
|
||||
|
||||
for token in tokenList:
|
||||
for token in infixTokens:
|
||||
if token == "(":
|
||||
opStack.push(token)
|
||||
elif token == ")":
|
||||
@ -36,7 +55,8 @@ def infixToPostfix(infixExp):
|
||||
while topToken != "(":
|
||||
postfixList.append(topToken)
|
||||
topToken = opStack.pop()
|
||||
elif token in "+-*/":
|
||||
elif isOperation(token):
|
||||
# On doit ajouter la condition == str sinon python ne veut pas tester l'appartenance à la chaine de caractère.
|
||||
while (not opStack.isEmpty()) and (priority[opStack.peek()] >= priority[token]):
|
||||
postfixList.append(opStack.pop())
|
||||
opStack.push(token)
|
||||
@ -46,23 +66,23 @@ def infixToPostfix(infixExp):
|
||||
while not opStack.isEmpty():
|
||||
postfixList.append(opStack.pop())
|
||||
|
||||
return " ".join(postfixList)
|
||||
return postfixList
|
||||
|
||||
def computePostfix(postfixExp):
|
||||
"""Compute a postfix expression
|
||||
def computePostfix(postfixTokens):
|
||||
"""Compute a postfix list of tokens
|
||||
|
||||
:param postfixExp: a postfix expression
|
||||
:returns: the result of the expression
|
||||
:param postfixTokens: a postfix list of tokens
|
||||
:returns: the result of the calculus
|
||||
|
||||
"""
|
||||
print(postfixToInfix(postfixExp))
|
||||
#print(postfixToInfix(postfixExp))
|
||||
# where to save numbers or
|
||||
operandeStack = Stack()
|
||||
|
||||
tokenList = postfixExp.split(" ")
|
||||
#tokenList = postfixExp.split(" ")
|
||||
|
||||
for (i,token) in enumerate(tokenList):
|
||||
if token in "+-*/":
|
||||
for (i,token) in enumerate(postfixTokens):
|
||||
if isOperation(token):
|
||||
op2 = operandeStack.pop()
|
||||
op1 = operandeStack.pop()
|
||||
res = doMath(token, op1, op2)
|
||||
@ -70,28 +90,29 @@ def computePostfix(postfixExp):
|
||||
|
||||
#print("Operation: {op1} {op} {op2}".format(op1 = op1, op = token, op2 = op2))
|
||||
#print(operandeStack)
|
||||
#print(tokenList[i+1:])
|
||||
newPostfix = " ".join(operandeStack + tokenList[i+1:])
|
||||
print(postfixToInfix(newPostfix))
|
||||
#print(postfixTokens[i+1:])
|
||||
newPostfix = " ".join(operandeStack + postfixTokens[i+1:])
|
||||
#print(postfixToInfix(newPostfix))
|
||||
|
||||
else:
|
||||
operandeStack.push(token)
|
||||
|
||||
return operandeStack.pop()
|
||||
|
||||
def computePostfixBis(postfixExp):
|
||||
"""Compute a postfix expression like a good student
|
||||
def computePostfixBis(postfixTokens):
|
||||
"""Compute a postfix list of tokens like a good student
|
||||
|
||||
:param postfixExp: a postfix expression
|
||||
:param postfixTokens: a postfix list of tokens
|
||||
:returns: the result of the expression
|
||||
|
||||
"""
|
||||
print(postfixExp)
|
||||
print(postfixToInfix(postfixExp))
|
||||
# where to save numbers or
|
||||
operandeStack = Stack()
|
||||
|
||||
tokenList = postfixExp.split(" ")
|
||||
#tokenList = postfixExp.split(" ")
|
||||
tokenList = postfixTokens.copy()
|
||||
|
||||
steps = []
|
||||
|
||||
steps = []
|
||||
|
||||
@ -100,11 +121,12 @@ def computePostfixBis(postfixExp):
|
||||
tmpTokenList = []
|
||||
# on va chercher les motifs du genre A B + pour les calculer
|
||||
while len(tokenList) > 2:
|
||||
if isNumber(tokenList[0]) and isNumber(tokenList[1]) and tokenList[2] in "+-*/":
|
||||
if isNumber(tokenList[0]) and isNumber(tokenList[1]) and isOperation(tokenList[2]):
|
||||
# S'il y a une opération à faire
|
||||
op1 = tokenList[0]
|
||||
op2 = tokenList[1]
|
||||
token = tokenList[2]
|
||||
|
||||
res = doMath(token, op1, op2)
|
||||
|
||||
tmpTokenList.append(res)
|
||||
@ -118,12 +140,9 @@ def computePostfixBis(postfixExp):
|
||||
tmpTokenList += tokenList
|
||||
|
||||
steps += expand_list(tmpTokenList)
|
||||
#print("----- Steps -----")
|
||||
#print(steps)
|
||||
|
||||
tokenList = steps[-1]
|
||||
tokenList = steps[-1].copy()
|
||||
|
||||
#print(postfixToInfix(tokenList))
|
||||
|
||||
return steps
|
||||
|
||||
@ -134,7 +153,7 @@ def isNumber(exp):
|
||||
:returns: True if the expression can be a number and false otherwise
|
||||
|
||||
"""
|
||||
return type(exp) == int or type(exp) == "Fraction"
|
||||
return type(exp) == int or type(exp) == Fraction
|
||||
|
||||
def isOperation(exp):
|
||||
"""Check if the expression is an opération in "+-*/"
|
||||
@ -155,28 +174,37 @@ def doMath(op, op1, op2):
|
||||
:returns: string representing the result
|
||||
|
||||
"""
|
||||
return str(eval(op1 + op + op2))
|
||||
operations = {"+": "__add__", "-": "__sub__", "*": "__mul__"}
|
||||
if op == "/":
|
||||
ans = [Fraction(op1, op2)]
|
||||
ans += ans[0].simplify()
|
||||
return ans
|
||||
else:
|
||||
return getattr(op1,operations[op])(op2)
|
||||
|
||||
|
||||
def postfixToInfix(postfixExp):
|
||||
"""Transforme postfix expression into infix expression
|
||||
|
||||
:param postfixExp: a postfix expression
|
||||
:returns: the corresponding infix expression
|
||||
def postfixToInfix(postfixTokens):
|
||||
"""Transforms postfix list of tokens into infix string
|
||||
|
||||
:param postfixTokens: a postfix list of tokens
|
||||
:returns: the corresponding infix string
|
||||
|
||||
"""
|
||||
operandeStack = Stack()
|
||||
|
||||
tokenList = postfixExp.split(" ")
|
||||
#print(postfixTokens)
|
||||
|
||||
for (i,token) in enumerate(tokenList):
|
||||
if token in "+-*/":
|
||||
#tokenList = postfixExp.split(" ")
|
||||
|
||||
for (i,token) in enumerate(postfixTokens):
|
||||
if isOperation(token):
|
||||
op2 = operandeStack.pop()
|
||||
if needPar(op2, token, "after"):
|
||||
op2 = "( " + op2 + " )"
|
||||
op2 = "( " + str(op2) + " )"
|
||||
op1 = operandeStack.pop()
|
||||
if needPar(op1, token, "before"):
|
||||
op1 = "( " + op1 + " )"
|
||||
op1 = "( " + str(op1) + " )"
|
||||
res = "{op1} {op} {op2}".format(op1 = op1, op = token, op2 = op2)
|
||||
|
||||
operandeStack.push(res)
|
||||
@ -194,16 +222,17 @@ def needPar(operande, operator, posi = "after"):
|
||||
:param posi: "after"(default) if the operande will be after the operator, "before" othewise
|
||||
:returns: bollean
|
||||
"""
|
||||
|
||||
priority = {"*" : 3, "/": 3, "+": 2, "-":2}
|
||||
|
||||
if type(operande)==int and operande < 0:
|
||||
if isNumber(operande) and operande < 0:
|
||||
return 1
|
||||
elif not isNumber(operande):
|
||||
# Si c'est une grande expression ou un chiffre négatif
|
||||
stand_alone = get_main_op(operande)
|
||||
# Si la priorité de l'operande est plus faible que celle de l'opérateur
|
||||
debug_var("stand_alone",stand_alone)
|
||||
debug_var("operande", type(operande))
|
||||
#debug_var("stand_alone",stand_alone)
|
||||
#debug_var("operande", type(operande))
|
||||
minor_priority = priority[get_main_op(operande)] < priority[operator]
|
||||
# Si l'opérateur est -/ pour after ou juste / pour before
|
||||
special = (operator in "-/" and posi == "after") or (operator in "/" and posi == "before")
|
||||
@ -212,10 +241,10 @@ def needPar(operande, operator, posi = "after"):
|
||||
else:
|
||||
return 0
|
||||
|
||||
def get_main_op(exp):
|
||||
"""Getting the main operation of the expression
|
||||
def get_main_op(tokens):
|
||||
"""Getting the main operation of the list of tokens
|
||||
|
||||
:param exp: the expression
|
||||
:param exp: the list of tokens
|
||||
:returns: the main operation (+, -, * or /) or 0 if the expression is only one element
|
||||
|
||||
"""
|
||||
@ -223,20 +252,20 @@ def get_main_op(exp):
|
||||
priority = {"*" : 3, "/": 3, "+": 2, "-":2}
|
||||
|
||||
parStack = Stack()
|
||||
tokenList = exp.split(" ")
|
||||
#tokenList = exp.split(" ")
|
||||
|
||||
if len(tokenList) == 1:
|
||||
if len(tokens) == 1:
|
||||
# Si l'expression n'est qu'un élément
|
||||
return 0
|
||||
|
||||
main_op = []
|
||||
|
||||
for token in tokenList:
|
||||
for token in tokens:
|
||||
if token == "(":
|
||||
parStack.push(token)
|
||||
elif token == ")":
|
||||
parStack.pop()
|
||||
elif token in "+-*/" and parStack.isEmpty():
|
||||
elif isOperation(token) and parStack.isEmpty():
|
||||
main_op.append(token)
|
||||
|
||||
return min(main_op, key = lambda s: priority[s])
|
||||
@ -279,9 +308,20 @@ def print_steps(steps):
|
||||
:returns: @todo
|
||||
|
||||
"""
|
||||
print("{first} \t = {sec}".format(first = steps[-1], sec = steps[-2]))
|
||||
for i in steps[-2:0:-1]:
|
||||
print("\t\t = ",i)
|
||||
print("{first} \t = {sec}".format(first = str_from_postfix(steps[0]), sec = str_from_postfix(steps[1])))
|
||||
for i in steps[2:]:
|
||||
print("\t\t = {i}".format(i=str_from_postfix(i)))
|
||||
|
||||
|
||||
def str_from_postfix(postfix):
|
||||
"""Return the string representing the expression
|
||||
|
||||
:param postfix: a postfix ordered list of tokens
|
||||
:returns: the corresponding string expression
|
||||
|
||||
"""
|
||||
infix = postfixToInfix(postfix)
|
||||
return infix
|
||||
|
||||
|
||||
def debug_var(name, var):
|
||||
@ -299,11 +339,14 @@ def test(exp):
|
||||
"""
|
||||
print("-------------")
|
||||
print("Expression ",exp)
|
||||
postfix = infixToPostfix(exp)
|
||||
tokens = str2tokens(exp)
|
||||
postfix = infixToPostfix(tokens)
|
||||
#print("Postfix " , postfix)
|
||||
#print(computePostfix(postfix))
|
||||
#print("Bis")
|
||||
steps = computePostfixBis(postfix)
|
||||
steps = [postfix]
|
||||
steps += computePostfixBis(postfix)
|
||||
print(steps)
|
||||
print_steps(steps)
|
||||
#print(postfixToInfix(postfix))
|
||||
#print(get_main_op(exp))
|
||||
@ -340,8 +383,8 @@ if __name__ == '__main__':
|
||||
#exp = "( 2 + 5 ) * ( 3 * 4 )"
|
||||
#test(exp)
|
||||
|
||||
exp = "( 2 + 5 - 1 ) / ( 3 * 4 )"
|
||||
test(exp)
|
||||
#exp = "( 2 + 5 - 1 ) / ( 3 * 4 )"
|
||||
#test(exp)
|
||||
|
||||
exp = "( 2 + 5 ) / ( 3 * 4 ) + 1 / 12"
|
||||
test(exp)
|
||||
@ -357,8 +400,8 @@ if __name__ == '__main__':
|
||||
## Ce denier pose un soucis. Pour le faire marcher il faudrai implémenter le calcul avec les fractions
|
||||
#exp = "( 2 + 5 ) / 3 * 4"
|
||||
#test(exp)
|
||||
#import doctest
|
||||
#doctest.testmod()
|
||||
import doctest
|
||||
doctest.testmod()
|
||||
|
||||
|
||||
# -----------------------------
|
||||
|
87
fraction.py
87
fraction.py
@ -1,7 +1,6 @@
|
||||
#!/usr/bin/env python
|
||||
# encoding: utf-8
|
||||
|
||||
from calculus import isNumber
|
||||
from arithmetic import gcd
|
||||
|
||||
class Fraction(object):
|
||||
@ -22,25 +21,25 @@ class Fraction(object):
|
||||
|
||||
:returns: steps to simplify the fraction or the fraction if there is nothing to do
|
||||
"""
|
||||
steps = [self]
|
||||
steps = []
|
||||
|
||||
if self._denom < 0:
|
||||
self._num = - self._num
|
||||
self._denom = - self._denom
|
||||
steps += [self]
|
||||
steps.append(self)
|
||||
|
||||
gcd_ = gcd(abs(self._num), abs(self._denom))
|
||||
if self._num == self._denom:
|
||||
self._num = 1
|
||||
self._denom = 1
|
||||
steps += [self]
|
||||
steps.append(self)
|
||||
|
||||
elif gcd_ != 1:
|
||||
self._num, self._denom = self._num // gcd_ , self._denom // gcd_
|
||||
steps += ["( {reste1} * {gcd} ) / ( {reste2} * {gcd} )".format(reste1 = self._num, reste2 = self._denom, gcd = gcd_)]
|
||||
steps.append("( {reste1} * {gcd} ) / ( {reste2} * {gcd} )".format(reste1 = self._num, reste2 = self._denom, gcd = gcd_))
|
||||
|
||||
# Certainement le truc le plus moche que j'ai jamais fait... On ne met que des strings dans steps puis au dernier moment on met une fraction. C'est moche de ma part
|
||||
steps += [self]
|
||||
steps.append(self)
|
||||
|
||||
return steps
|
||||
|
||||
@ -50,8 +49,8 @@ class Fraction(object):
|
||||
else:
|
||||
return str(self._num) + " / " + str(self._denom)
|
||||
|
||||
#def __repr__(self):
|
||||
# return self.__str__()
|
||||
def __repr__(self):
|
||||
return "< Fraction " + self.__str__() + ">"
|
||||
|
||||
def __add__(self, other):
|
||||
if type(other) == Fraction:
|
||||
@ -60,7 +59,7 @@ class Fraction(object):
|
||||
else:
|
||||
number = Fraction(other)
|
||||
|
||||
steps = ["{frac1} + {frac2}".format(frac1 = self, frac2 = number)]
|
||||
steps = []
|
||||
|
||||
if self._denom == number._denom:
|
||||
com_denom = self._denom
|
||||
@ -72,17 +71,18 @@ class Fraction(object):
|
||||
coef1 = number._denom // gcd_denom
|
||||
coef2 = self._denom // gcd_denom
|
||||
|
||||
steps += ["( {num1} * {coef1} ) / ( {den1} * {coef1} ) + ( {num2} * {coef2} ) / ( {den2} * {coef2} )".format(num1 = self._num, den1 = self._denom, coef1 = coef1, num2 = number._num, den2 = number._denom, coef2 = coef2)]
|
||||
steps.append("( {num1} * {coef1} ) / ( {den1} * {coef1} ) + ( {num2} * {coef2} ) / ( {den2} * {coef2} )".format(num1 = self._num, den1 = self._denom, coef1 = coef1, num2 = number._num, den2 = number._denom, coef2 = coef2))
|
||||
|
||||
com_denom = self._denom * coef1
|
||||
num1 = self._num * coef1
|
||||
num2 = number._num * coef2
|
||||
|
||||
steps += ["( {num1} + {num2} ) / {denom}".format(num1 = num1, num2 = num2, denom = com_denom)]
|
||||
steps.append("( {num1} + {num2} ) / {denom}".format(num1 = num1, num2 = num2, denom = com_denom))
|
||||
|
||||
num = num1 + num2
|
||||
|
||||
ans_frac = Fraction(num, com_denom)
|
||||
steps.append(ans_frac)
|
||||
steps += ans_frac.simplify()
|
||||
|
||||
return steps
|
||||
@ -94,7 +94,7 @@ class Fraction(object):
|
||||
else:
|
||||
number = Fraction(other)
|
||||
|
||||
steps = ["{frac1} - {frac2}".format(frac1 = self, frac2 = number)]
|
||||
steps = []
|
||||
|
||||
if self._denom == number._denom:
|
||||
com_denom = self._denom
|
||||
@ -106,17 +106,18 @@ class Fraction(object):
|
||||
coef1 = number._denom // gcd_denom
|
||||
coef2 = self._denom // gcd_denom
|
||||
|
||||
steps += ["( {num1} * {coef1} ) / ( {den1} * {coef1} ) - ( {num2} * {coef2} ) / ( {den2} * {coef2} )".format(num1 = self._num, den1 = self._denom, coef1 = coef1, num2 = number._num, den2 = number._denom, coef2 = coef2)]
|
||||
steps.append("( {num1} * {coef1} ) / ( {den1} * {coef1} ) - ( {num2} * {coef2} ) / ( {den2} * {coef2} )".format(num1 = self._num, den1 = self._denom, coef1 = coef1, num2 = number._num, den2 = number._denom, coef2 = coef2))
|
||||
|
||||
com_denom = self._denom * coef1
|
||||
num1 = self._num * coef1
|
||||
num2 = number._num * coef2
|
||||
|
||||
steps += ["( {num1} - {num2} ) / {denom}".format(num1 = num1, num2 = num2, denom = com_denom)]
|
||||
steps.append("( {num1} - {num2} ) / {denom}".format(num1 = num1, num2 = num2, denom = com_denom))
|
||||
|
||||
num = num1 - num2
|
||||
|
||||
ans_frac = Fraction(num, com_denom)
|
||||
steps.append(ans_frac)
|
||||
steps += ans_frac.simplify()
|
||||
|
||||
return steps
|
||||
@ -128,13 +129,14 @@ class Fraction(object):
|
||||
else:
|
||||
number = Fraction(other)
|
||||
|
||||
steps = ["( {frac1} ) * ( {frac2} )".format(frac1 = self, frac2 = number)]
|
||||
steps += ["( {num1} * {num2} ) / ( {denom1} * {denom2} )".format(num1 = self._num, num2 = number._num, denom1 = self._denom, denom2 = number._denom)]
|
||||
steps = []
|
||||
steps.append("( {num1} * {num2} ) / ( {denom1} * {denom2} )".format(num1 = self._num, num2 = number._num, denom1 = self._denom, denom2 = number._denom))
|
||||
|
||||
num = self._num * number._num
|
||||
denom = self._denom * number._denom
|
||||
|
||||
ans_frac = Fraction(num, denom)
|
||||
steps.append(ans_frac)
|
||||
steps += ans_frac.simplify()
|
||||
|
||||
return steps
|
||||
@ -146,18 +148,29 @@ class Fraction(object):
|
||||
else:
|
||||
number = Fraction(other)
|
||||
|
||||
steps = ["( {frac1} ) / ( {frac2} )".format(frac1 = self, frac2 = number)]
|
||||
steps = []
|
||||
number = Fraction(number._denom, number._num)
|
||||
steps += self * number
|
||||
|
||||
return steps
|
||||
|
||||
def __lt__(self, other):
|
||||
if type(other) == Fraction:
|
||||
return (self._num / self._denom) < (other._num / other._denom)
|
||||
else:
|
||||
return (self._num / self._denom) < other
|
||||
|
||||
def __le__(self, other):
|
||||
if type(other) == Fraction:
|
||||
return (self._num / self._denom) <= (other._num / other._denom)
|
||||
else:
|
||||
return (self._num / self._denom) <= other
|
||||
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
f = Fraction(34, 12)
|
||||
g = Fraction(1,5)
|
||||
f = Fraction(1, 12)
|
||||
g = Fraction(1, 12)
|
||||
h = Fraction(-1,5)
|
||||
t = Fraction(-4,5)
|
||||
print("---------")
|
||||
@ -169,24 +182,24 @@ if __name__ == '__main__':
|
||||
print("---------")
|
||||
for i in (f + g):
|
||||
print(i)
|
||||
print("---------")
|
||||
for i in (f - g):
|
||||
print(i)
|
||||
print("---------")
|
||||
for i in (f * g):
|
||||
print(i)
|
||||
print("---------")
|
||||
for i in (h + t):
|
||||
print(i)
|
||||
print("---------")
|
||||
for i in (h - t):
|
||||
print(i)
|
||||
print("---------")
|
||||
for i in (h * t):
|
||||
print(i)
|
||||
print("---------")
|
||||
for i in (h / t):
|
||||
print(i)
|
||||
#print("---------")
|
||||
#for i in (f - g):
|
||||
# print(i)
|
||||
#print("---------")
|
||||
#for i in (f * g):
|
||||
# print(i)
|
||||
#print("---------")
|
||||
#for i in (h + t):
|
||||
# print(i)
|
||||
#print("---------")
|
||||
#for i in (h - t):
|
||||
# print(i)
|
||||
#print("---------")
|
||||
#for i in (h * t):
|
||||
# print(i)
|
||||
#print("---------")
|
||||
#for i in (h / t):
|
||||
# print(i)
|
||||
|
||||
#print(f.simplify())
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user