evaluate_expression
Evaluate mathematical expressions with support for arithmetic, trigonometric functions, logarithms, and constants. Uses explicit operators and scientific notation.
Instructions
Evaluate a mathematical expression. PRIMARY tool for ALL math: +, -, *, /, %, ^. Functions: sqrt, sin, cos, tan, asin, acos, atan, log10, ln, log(x,base), abs, round, floor, ceil, min, max. Constants: pi, e, tau, phi, sqrt2, euler_mascheroni, c, g, G, h, k, R, NA, e_charge, m_e, m_p. Parentheses and scientific notation (1e6) supported. Use explicit operators: 2 * pi, not 2pi.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| expression | Yes |
Implementation Reference
- cruncher.js:895-912 (schema)Input schema and registration for the evaluate_expression tool. Defines the tool name, description, and inputSchema requiring a single 'expression' string parameter.
// --- NEW in v1.2.0: Expression Evaluator --- { name: "evaluate_expression", annotations: { title: "Evaluate Expression", readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false, }, description: "Evaluate a mathematical expression. PRIMARY tool for ALL math: +, -, *, /, %, ^. Functions: sqrt, sin, cos, tan, asin, acos, atan, log10, ln, log(x,base), abs, round, floor, ceil, min, max. Constants: pi, e, tau, phi, sqrt2, euler_mascheroni, c, g, G, h, k, R, NA, e_charge, m_e, m_p. Parentheses and scientific notation (1e6) supported. Use explicit operators: 2 * pi, not 2pi.", inputSchema: { type: "object", properties: { expression: { type: "string" } }, required: ["expression"], }, }, - cruncher.js:173-224 (helper)Constants definitions (CONSTANTS) and pre-compiled regex patterns used by evaluate_expression for constant substitution, function-to-Math mapping, and security validation.
const CONSTANTS = { // Math pi: Math.PI, e: Math.E, tau: 2 * Math.PI, phi: 1.618033988749895, sqrt2: Math.SQRT2, euler_mascheroni: 0.5772156649015329, // Physics (SI Units) c: 299792458, g: 9.80665, G: 6.6743e-11, h: 6.62607015e-34, k: 1.380649e-23, R: 8.314462618, NA: 6.02214076e23, e_charge: 1.602176634e-19, m_e: 9.1093837015e-31, m_p: 1.67262192369e-27, }; // --- Pre-compiled Regex for evaluate_expression --- const RE_NOTATION_CARAT = /\^/g; const RE_SCIENTIFIC_NOTATION = /(\d+\.?\d*)e([+-]?\d+)/gi; const RE_FUNC_ABS = /\babs\s*\(/g; const RE_FUNC_ROUND = /\bround\s*\(/g; const RE_FUNC_FLOOR = /\bfloor\s*\(/g; const RE_FUNC_CEIL = /\bceil\s*\(/g; const RE_FUNC_MIN_FUNC = /\bmin\s*\(/g; const RE_FUNC_MAX_FUNC = /\bmax\s*\(/g; // Trigonometric functions (radians only — same as standard math) const RE_FUNC_SIN = /\bsin\s*\(/g; const RE_FUNC_COS = /\bcos\s*\(/g; const RE_FUNC_TAN = /\btan\s*\(/g; const RE_FUNC_ASIN = /\basin\s*\(/g; const RE_FUNC_ACOS = /\bacos\s*\(/g; const RE_FUNC_ATAN = /\batan\s*\(/g; // Math helpers const RE_FUNC_SQRT = /\bsqrt\s*\(/g; const RE_FUNC_LOG = /\blog10\s*\(/g; // log10() → Math.log10() const RE_FUNC_LN = /\bln\s*\(/g; // ln() → Math.log() const RE_FUNC_LOG_BASE = /\blog\s*\(([^,)]+)\s*,\s*([^)]+)\)/g; // log(x,base) // Constants pattern: longest names first to avoid partial matches (e_charge before e, // euler_mascheroni before e, sqrt2 before pi, tau before tau). Built dynamically. const RE_CONSTANTS = (() => { const names = Object.keys(CONSTANTS).sort((a, b) => b.length - a.length); const escaped = names.map(n => n.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')); return new RegExp(`\\b(${escaped.join('|')})\\b`, 'g'); })(); const RE_DISALLOWED_CHARS = /[^0-9+\-*/().% \t*,Mathabspowrndflceigumsxqtogv1]/; const RE_VALID_MATH_CALLS = /Math\.(pow|abs|round|floor|ceil|min|max|sin|cos|tan|asin|acos|atan|sqrt|log10|log)\(/g; - cruncher.js:1744-1827 (handler)The evaluate_expression handler function. Transforms expression string by replacing ^ with **, converting scientific notation, mapping functions (abs, sin, cos, etc.) to Math.*, substituting constants, and then safely evaluating via new Function(). Includes security whitelist check and infinity/NaN error handling.
evaluate_expression: ({ expression }) => { // Pre-compiled regexes for expression preprocessing // 1. Convert mathematical ^ to JavaScript's ** operator let parsedExpr = expression.replace(RE_NOTATION_CARAT, "**"); // 2. Convert scientific notation (1e6, 2.5e-3) to safe multiplication parsedExpr = parsedExpr.replace( RE_SCIENTIFIC_NOTATION, "($1 * Math.pow(10, $2))" ); // 3. Convert built-in functions to Math.* equivalents parsedExpr = parsedExpr .replace(RE_FUNC_ABS, "Math.abs(") .replace(RE_FUNC_ROUND, "Math.round(") .replace(RE_FUNC_FLOOR, "Math.floor(") .replace(RE_FUNC_CEIL, "Math.ceil(") .replace(RE_FUNC_MIN_FUNC, "Math.min(") .replace(RE_FUNC_MAX_FUNC, "Math.max(") // Trigonometric (radians — standard math convention) .replace(RE_FUNC_SIN, "Math.sin(") .replace(RE_FUNC_COS, "Math.cos(") .replace(RE_FUNC_TAN, "Math.tan(") .replace(RE_FUNC_ASIN, "Math.asin(") .replace(RE_FUNC_ACOS, "Math.acos(") .replace(RE_FUNC_ATAN, "Math.atan(") // Math helpers .replace(RE_FUNC_SQRT, "Math.sqrt(") .replace(RE_FUNC_LOG, "Math.log10(") .replace(RE_FUNC_LN, "Math.log("); // 3.1. Handle log(x, base) → Math.log(x) / Math.log(base) parsedExpr = parsedExpr.replace(RE_FUNC_LOG_BASE, "Math.log($1) / Math.log($2)"); // 3.5. Substitute constant names with their numeric values // 3.5. Substitute constant names with their numeric values // e.g., "pi * 2" → "3.141592653589793 * 2" // Use word boundaries so "pi" doesn't match inside other identifiers. // Longest constant names are matched first to avoid partial collisions. // Required explicit operator: "2 * pi", not "2pi". parsedExpr = parsedExpr.replace(RE_CONSTANTS, (match) => CONSTANTS[match].toString()); // 4. SECURITY CHECK: Strict Whitelist if (RE_DISALLOWED_CHARS.test(parsedExpr)) { throw new Error( "Security Error: Expression contains invalid characters. " + "Only numbers, basic operators (+, -, *, /, %, ^), parentheses, commas, " + "functions (abs, round, floor, ceil, min, max, sin, cos, tan, asin, acos, atan, sqrt, log10, ln, log) " + "and constants (pi, e, tau, phi, sqrt2, c, g, G, h, k, R, NA, euler_mascheroni) " + "are allowed.", ); } // Verify only valid Math.* functions remain const sanitizedExpr = parsedExpr.replace(RE_VALID_MATH_CALLS, ""); if (sanitizedExpr.includes("Math.")) { throw new Error( "Security Error: Invalid Math function. " + "Only abs, round, floor, ceil, min, max, pow, sin, cos, tan, asin, acos, atan, sqrt, log10, log are allowed.", ); } try { // 5. Evaluate safely // Because we strictly verified the contents above, this is now safe to run. const result = new Function("return (" + parsedExpr + ")")(); if (result === Infinity || result === -Infinity) { throw new Error( "Domain Error: Expression evaluated to infinity. " + "Check for division by zero or overflow (e.g., exp(1000)).", ); } if (isNaN(result)) { // Try to give a more helpful message by re-evaluating sub-expressions throw new Error( "Domain Error: Expression evaluated to NaN. " + "Check for: sqrt(negative), log(negative/zero), asin/acos out of [-1,1], or 0/0.", ); } return result; } catch (error) { throw new Error("Failed to evaluate expression: " + error.message); } },