Форум сайта python.su
857
odnochlenв смысле O(n) на O(1) ?
Ну и c in ‘0123456789’ стоило бы заменить на c in set('0123456789').
Офлайн
1
Не могу не похвастаться, что все заработало как надо. Еще интерфейс на Qt запилю, и тогда вообще будет сказка
Спасибо вам огромное, дорогой py.user.next!
#! /usr/bin/env python # ------loads from MATH module, you can change this list------ FUNCTIONS = ['sin', 'cos', 'tan', 'sqrt', 'log'] # ------------------------------------------------------------ # Expression: # Term # Expression + Term # Expression - Term # Term: # Primary # Term * Primary # Term / Primary # Term % Primary # Primary: # Number # ( Expression ) # function ( Expression ) # - Primary # + Primary # Number: # floating-point-literal class Buffer(list): def get(self): if self: return self.pop(0) def putback(self, val): self.insert(0, val) def expression(buf): left = term(buf) t = buf.get() while True: if t == '+': left += term(buf) t = buf.get() elif t == '-': left -= term(buf) t = buf.get() else: buf.putback(t) return left def term(buf): left = primary(buf) t = buf.get() while True: if t == '*': left *= primary(buf) t = buf.get() elif t == '/': d = primary(buf) if d == 0.: raise ValueError('divide by zero') left /= d t = buf.get() elif t == '%': d = primary(buf) if d == 0.: raise ValueError('divide by zero') left %= d t = buf.get() else: buf.putback(t) return left import math def primary(buf): t = buf.get() if isint(t): return int(t) elif isfloat(t): return float(t) elif t == '-': return - primary(buf) elif t == '+': return primary(buf) elif t == '(': d = expression(buf) t = buf.get() if t != ')': raise ValueError("')' expected") return d elif t in FUNCTIONS: return getattr(math, str(t))(primary(buf)) else: raise ValueError('primary expected') def isint(string): try: int(string) return True except ValueError: return False def isfloat(string): try: float(string) return True except ValueError: return False NUMBERS = '0123456789' PERIOD = '.' SYMBOLS = '()+-*/%' NUMBERS_WITH_PERIOD = PERIOD + NUMBERS FUNCTIONS_str = ''.join(FUNCTIONS) def p(s): res = [] s = ''.join(s.split()) state = 'normal' slen = len(s) eword = '' i = 0 while i < slen: c = s[i] if state == 'normal': if c in NUMBERS_WITH_PERIOD: state = 'number' num = '' was_period = False elif c in SYMBOLS: state = 'symbol' elif c in FUNCTIONS_str: state = 'function' func = '' else: state = 'error' i -= 1 elif state == 'number': if c in NUMBERS: num += c elif c == PERIOD: if was_period: eword = c state = 'error' i -= 1 else: num += c was_period = True if c not in NUMBERS_WITH_PERIOD: res.append(num) num = '' state = 'normal' i -= 1 if i + 1 == slen: res.append(num) elif state == 'symbol': if c in SYMBOLS: res.append(c) else: state = 'normal' i -= 1 elif state == 'function': if c in FUNCTIONS_str: func += c if c not in FUNCTIONS_str: if func in FUNCTIONS: res.append(func) state = 'normal' else: eword = func state = 'error' i -= 1 if i + 1 == slen: if func in FUNCTIONS: res.append(func) else: eword = func state = 'error' i -= 1 elif state == 'error': raise ValueError("wrong word '{}'".format(eword)) i += 1 return res def calc(expr): return expression(Buffer(p(expr))) if __name__ == "__main__": from time import time from math import * exprs = ['(3+2+1+9/2-98*5+7%2)-2+4/2+(((321)-43)-1)/2.', '-2-1', '(+2-1)/.100', '.311-2/4.5', '10%3', 'sqrt(12)', 'sqrt(4)-1+cos(33)', 'log(20)'] for e in exprs: t1 = time() e1 = eval(e) t1 -= time() t2 = time() e2 = calc(e) t2 -= time() print "eval({0}):\t{1}\t{2:10f}\ncalc({0}):\t{3}\t{4:10f}\n".format(e, e1, t1, e2, t2)
Офлайн