# Shared calculator tool for the "with calculator" round. Safe arithmetic only (+ - * / parentheses, decimals). import ast, operator as o from decimal import Decimal OPS={ast.Add:o.add,ast.Sub:o.sub,ast.Mult:o.mul,ast.Div:o.truediv,ast.USub:o.neg,ast.UAdd:o.pos} def _ev(n): if isinstance(n,ast.Expression): return _ev(n.body) if isinstance(n,ast.Constant) and isinstance(n.value,(int,float)): return Decimal(str(n.value)) if isinstance(n,ast.BinOp) and type(n.op) in OPS: return OPS[type(n.op)](_ev(n.left),_ev(n.right)) if isinstance(n,ast.UnaryOp) and type(n.op) in OPS: return OPS[type(n.op)](_ev(n.operand)) raise ValueError("only + - * / ( ) and numbers are allowed") CALLS=[] def calculate(expression: str) -> str: """Evaluate an arithmetic expression exactly, e.g. '1840.20 + 960 - 1250'. Supports + - * / and parentheses.""" try: r=str(_ev(ast.parse(expression.replace(",",""),mode="eval"))) except Exception as e: r=f"error: {e}" CALLS.append((expression,r)); return r NOTE="\n\nYou have a `calculate` tool. Use it for every arithmetic step; do not do sums in your head." def report(): print(f"\nTOOL_CALLS {len(CALLS)}"); [print(" CALC",e,"=",r) for e,r in CALLS]