{"slug": "beyond-eval-how-i-built-a-step-by-step-math-calculator-that-explains-its-work-ai", "title": "Beyond 'eval()': How I Built a Step-by-Step Math Calculator That Explains Its Work with AI", "summary": "A developer built a step-by-step math calculator that explains its work using an AI model combined with LaTeX and MathJax. The tool handles arithmetic, algebra, fractions, and word problems, avoiding eval() for security and clarity. The AI provides flexible reasoning while normal code manages the interface and formatting.", "body_md": "Building a calculator that returns an answer takes little code.\n\nBuilding one that explains **how it reached that answer** creates a different problem.\n\nTake this expression:\n\n```\n12 + 6 × 3\n```\n\nJavaScript can calculate the result with simple code.\n\n``` js\nconst result = 12 + 6 * 3;\n\nconsole.log(result);\n// 30\n```\n\nThat gives the correct answer.\n\nIt does not explain the work.\n\nA student may need to see this:\n\n```\n12 + 6 × 3\n\nStep 1:\nMultiply 6 by 3.\n\n6 × 3 = 18\n\nStep 2:\nAdd 12 and 18.\n\n12 + 18 = 30\n\nFinal answer:\n30\n```\n\nThat difference between **calculating** and **explaining** became the main challenge when I worked on a step-by-step math calculator.\n\nI wanted something that could handle more than basic arithmetic.\n\nThe calculator needed to work with equations, fractions, algebra, percentages, calculus, word problems, and other math questions.\n\nI also wanted clean mathematical notation.\n\nThat meant solving several separate problems:\n\nI ended up using an AI model together with normal application code, LaTeX, and MathJax.\n\nThe AI handles the flexible reasoning.\n\nLaTeX describes the math.\n\nMathJax turns the LaTeX into readable mathematical notation.\n\nJavaScript handles the interface and application logic.\n\n`eval()`\n\nis not enough\nA basic JavaScript calculator often starts with something like this:\n\n``` js\nconst expression = \"12 + 6 * 3\";\nconst answer = eval(expression);\n\nconsole.log(answer);\n```\n\nThere are two problems with this approach.\n\nThe first problem is security.\n\nPassing raw user input to `eval()`\n\ncan execute JavaScript. That makes it a poor choice for a public calculator.\n\nThe second problem matters even more here.\n\n`eval()`\n\ngives me this:\n\n```\n30\n```\n\nIt does not give me this:\n\n```\n6 × 3 = 18\n12 + 18 = 30\n```\n\nIt also cannot explain why multiplication happens before addition.\n\nThe limitation becomes clearer with algebra.\n\nConsider:\n\n```\n2x + 5 = 17\n```\n\nA useful result should look like this:\n\n```\n2x + 5 = 17\n\nSubtract 5 from both sides.\n\n2x = 12\n\nDivide both sides by 2.\n\nx = 6\n```\n\nJavaScript does not understand `2x + 5 = 17`\n\nas a normal JavaScript expression.\n\nA step-by-step solver needs more than expression evaluation.\n\nOne option would be to write custom solving logic for every type of math.\n\nI could start with addition.\n\nThen subtraction.\n\nThen multiplication.\n\nThen division.\n\nThen fractions.\n\nThen percentages.\n\nThen linear equations.\n\nThen quadratic equations.\n\nThen powers and roots.\n\nThen logarithms.\n\nThen derivatives.\n\nThen integrals.\n\nThe amount of code would keep growing.\n\nEven one category contains many different forms.\n\nA linear equation might look like this:\n\n```\n2x + 5 = 17\n```\n\nIt might also look like this:\n\n```\n4(x - 2) = 20\n```\n\nOr:\n\n```\n3x + 7 = x + 19\n```\n\nThe steps change for each case.\n\nWord problems create another issue.\n\n```\nA rectangle has a length of 12 cm and a width of 7 cm.\nWhat is its area?\n```\n\nA normal expression parser first needs to understand the sentence.\n\nIt then needs to identify the correct formula.\n\nOnly after that can it calculate the answer.\n\nI did not want to create thousands of explanation rules by hand.\n\nThat is where an AI model became useful.\n\nI do not treat the AI model as the whole application.\n\nIt handles the part that benefits from flexible reasoning and language.\n\nThe rest of the system still uses normal code.\n\nA simplified flow looks like this:\n\n```\nUser enters a problem\n        ↓\nApplication processes the input\n        ↓\nSolver receives the problem\n        ↓\nAI works through the solution\n        ↓\nAI returns structured output\n        ↓\nApplication checks the response\n        ↓\nMathJax formats the math\n        ↓\nSteps appear in the browser\n```\n\nThe model can understand different forms of math without requiring one hard-coded path for every possible question.\n\nThat does not mean the model gets full control.\n\nThe application still decides how the response should look and how it should reach the screen.\n\nI do not want the model to return a random block of text.\n\nA response like this is difficult to control:\n\n```\nOkay! Let's solve this problem. First we need to...\n```\n\nThe wording may change on every request.\n\nThe frontend also has to guess where one step ends and another begins.\n\nStructured output works better.\n\nFor example:\n\n```\n{\n  \"finalAnswer\": \"\\\\(x = 6\\\\)\",\n  \"steps\": [\n    {\n      \"explanation\": \"Start with the equation.\",\n      \"math\": \"\\\\[2x + 5 = 17\\\\]\"\n    },\n    {\n      \"explanation\": \"Subtract 5 from both sides.\",\n      \"math\": \"\\\\[2x = 12\\\\]\"\n    },\n    {\n      \"explanation\": \"Divide both sides by 2.\",\n      \"math\": \"\\\\[x = 6\\\\]\"\n    }\n  ]\n}\n```\n\nNow the roles stay clear.\n\nThe AI produces the solution data.\n\nThe application controls the interface.\n\nThis gives me much more predictable output.\n\nGetting the correct steps from AI solves only part of the problem.\n\nMath can look bad in plain text.\n\nTake the quadratic formula.\n\nThe AI could return:\n\n```\nx = (-b +- sqrt(b^2 - 4ac)) / 2a\n```\n\nA human can understand it.\n\nIt does not look like proper mathematical notation.\n\nLaTeX gives the model a standard way to describe the expression.\n\n```\nx = \\frac{-b \\pm \\sqrt{b^2 - 4ac}}{2a}\n```\n\nThe same approach works for fractions:\n\n```\n\\frac{3x + 2}{x - 5}\n```\n\nSquare roots:\n\n```\n\\sqrt{x^2 + 9}\n```\n\nPowers:\n\n```\nx^{12}\n```\n\nIntegrals:\n\n```\n\\int_0^5 x^2 \\, dx\n```\n\nMatrices:\n\n```\n\\begin{bmatrix}\n1 & 2 \\\\\n3 & 4\n\\end{bmatrix}\n```\n\nLaTeX gives the application one consistent format for mathematical expressions.\n\nThe AI does not need to invent a different visual style for every problem.\n\nLaTeX is still text.\n\nA browser does not automatically turn this:\n\n```\n\\[\\frac{x+2}{3}=7\\]\n```\n\ninto a properly formatted equation.\n\nThat is where MathJax comes in.\n\nThe full flow looks more like this:\n\n```\nUser Input\n    ↓\nInput Processing\n    ↓\nSolver Router\n    ↓\nAI or Local Math Engine\n    ↓\nValidation\n    ↓\nStructured JSON\n    ↓\nLaTeX Expressions\n    ↓\nMathJax\n    ↓\nStep-by-Step Interface\n```\n\nThe AI decides what the solution should contain.\n\nLaTeX describes the mathematical notation.\n\nMathJax renders that notation inside the page.\n\nEach part has one clear job.\n\nThe prompt matters a lot.\n\nI do not send only:\n\n```\nSolve this:\n2x + 5 = 17\n```\n\nThat gives the model too much freedom.\n\nI define the expected output.\n\nA simplified prompt might look like this:\n\n```\nSolve the math problem step by step.\n\nKeep each explanation short.\n\nDo not skip important operations.\n\nReturn mathematical expressions as LaTeX.\n\nUse \\( ... \\) for inline math.\n\nUse \\[ ... \\] for equations that should appear on their own line.\n\nDo not return HTML.\n\nDo not place LaTeX inside Markdown code blocks.\n\nReturn valid JSON.\n\nUse this structure:\n\n{\n  \"finalAnswer\": \"\",\n  \"steps\": [\n    {\n      \"explanation\": \"\",\n      \"math\": \"\"\n    }\n  ]\n}\n```\n\nI can also add instructions for specific types of problems.\n\nFor algebra:\n\n```\nShow what operation happens to both sides of the equation.\n```\n\nFor fractions:\n\n```\nShow the common denominator when one is required.\n```\n\nFor calculus:\n\n```\nState the rule used before applying it.\n```\n\nThe prompt does not need to teach mathematics from scratch.\n\nThe model already handles the reasoning.\n\nThe prompt defines how I want the result delivered.\n\nThere is one small detail that can cause confusing bugs.\n\nLaTeX uses backslashes.\n\nFor example:\n\n```\n\\frac{3}{4}\n```\n\nJSON strings also use backslashes for escaping.\n\nThat means serialized JSON may contain:\n\n```\n{\n  \"math\": \"\\\\[\\\\frac{3}{4}\\\\]\"\n}\n```\n\nThe double backslashes are normal.\n\nAfter JavaScript parses the JSON, the string becomes the LaTeX expression that MathJax needs.\n\nThis matters for commands such as:\n\n```\n\\frac\n\\sqrt\n\\times\n\\div\n\\int\n```\n\nIncorrect escaping can break otherwise valid AI output.\n\nA page can load MathJax from a content delivery network.\n\nA simple setup can look like this:\n\n```\n<script>\nwindow.MathJax = {\n  tex: {\n    inlineMath: [\n      ['\\\\(', '\\\\)']\n    ],\n    displayMath: [\n      ['\\\\[', '\\\\]']\n    ]\n  }\n};\n</script>\n\n<script\n  defer\n  src=\"https://cdn.jsdelivr.net/npm/mathjax@4/tex-svg.js\">\n</script>\n```\n\nI prefer explicit delimiters.\n\nInline math uses:\n\n```\n\\( x = 6 \\)\n```\n\nDisplay math uses:\n\n```\n\\[ x = 6 \\]\n```\n\nThis also avoids depending only on dollar signs.\n\nDollar signs can appear in normal text.\n\nTake this question:\n\n```\nA $50 product gets a 20% discount.\nWhat is the new price?\n```\n\nUsing `$...$`\n\nas the only delimiter can create problems when the input contains currency.\n\nThe `\\(...\\)`\n\nand `\\[...\\]`\n\ndelimiters make the boundary much clearer.\n\nThis part matters in an AI calculator.\n\nMathJax can process equations that already exist when the page loads.\n\nAI responses arrive later.\n\nThe user enters a problem.\n\nJavaScript sends a request.\n\nThe server returns the solution.\n\nJavaScript then adds those new steps to the page.\n\nMathJax needs to process that new content.\n\nA simplified renderer could look like this:\n\n``` js\nasync function renderSolution(solution) {\n  const container = document.querySelector(\"#solution\");\n\n  container.replaceChildren();\n\n  solution.steps.forEach((step, index) => {\n    const section = document.createElement(\"section\");\n\n    const heading = document.createElement(\"h3\");\n    heading.textContent = `Step ${index + 1}`;\n\n    const explanation = document.createElement(\"p\");\n    explanation.textContent = step.explanation;\n\n    const math = document.createElement(\"div\");\n    math.textContent = step.math;\n\n    section.append(\n      heading,\n      explanation,\n      math\n    );\n\n    container.appendChild(section);\n  });\n\n  const finalAnswer = document.createElement(\"div\");\n\n  finalAnswer.textContent =\n    `Final answer: ${solution.finalAnswer}`;\n\n  container.appendChild(finalAnswer);\n\n  await MathJax.typesetPromise([container]);\n}\n```\n\nThe important part is:\n\n```\nawait MathJax.typesetPromise([container]);\n```\n\nThe AI response already exists inside the container at that point.\n\nMathJax scans it and finds the LaTeX delimiters.\n\nIt then renders the equations.\n\nWithout that final step, users would see raw strings such as:\n\n```\n\\[\\frac{3}{4} + \\frac{1}{2}\\]\n```\n\ninstead of properly formatted math.\n\nI prefer this structure:\n\n```\n{\n  \"explanation\": \"Subtract 5 from both sides.\",\n  \"math\": \"\\\\[2x = 12\\\\]\"\n}\n```\n\ninstead of:\n\n```\n{\n  \"step\": \"Subtract 5 from both sides so \\\\(2x = 12\\\\)\"\n}\n```\n\nKeeping them separate gives the frontend more control.\n\nThe explanation can use normal paragraph styling.\n\nThe equation can have more space around it.\n\nMathJax only needs to handle the mathematical part.\n\nThe layout also becomes easier to adapt for phones.\n\nIt might seem easier to ask the model for this:\n\n```\n<p>Subtract 5 from both sides.</p>\n<div>2x = 12</div>\n```\n\nI avoid that approach.\n\nThe model should return data.\n\nThe application should create the markup.\n\nI prefer:\n\n```\n{\n  \"explanation\": \"Subtract 5 from both sides.\",\n  \"math\": \"\\\\[2x = 12\\\\]\"\n}\n```\n\nThen JavaScript creates the elements.\n\nThis keeps the application structure predictable.\n\nIt also gives the model less control over the page.\n\nI would avoid doing this with raw model output:\n\n```\ncontainer.innerHTML = modelResponse;\n```\n\nAI output should count as untrusted input.\n\nCreating elements and using `textContent`\n\ngives the application much more control.\n\n```\nexplanation.textContent = step.explanation;\nmath.textContent = step.math;\n```\n\nMathJax can process the mathematical string after JavaScript adds it to the document.\n\nThe model controls the equation.\n\nIt does not control the page markup.\n\nAn AI-powered calculator needs access to an AI service.\n\nThat usually means an API key.\n\nThe key should stay on the server.\n\nIt should not appear inside public browser JavaScript.\n\nThis is unsafe:\n\n``` js\nconst API_KEY = \"my-secret-api-key\";\n```\n\nAnyone can inspect the page source or network activity.\n\nInstead, the browser sends the problem to an endpoint on my own server.\n\nA simplified example looks like this:\n\n``` js\nasync function solveProblem(problem) {\n  const response = await fetch(\"/api/solve\", {\n    method: \"POST\",\n    headers: {\n      \"Content-Type\": \"application/json\"\n    },\n    body: JSON.stringify({\n      problem\n    })\n  });\n\n  if (!response.ok) {\n    throw new Error(\"Unable to solve the problem\");\n  }\n\n  return response.json();\n}\n```\n\nThe server talks to the AI provider.\n\nThe browser never receives the secret key.\n\nThe server can also apply rate limits and input limits before spending money on a model request.\n\nAI gives the calculator flexibility.\n\nIt does not guarantee perfection.\n\nA language model can make calculation mistakes.\n\nIt can miss a negative sign.\n\nIt can misunderstand ambiguous input.\n\nIt can also give a clean explanation for an incorrect answer.\n\nThat means the application should verify whatever it can.\n\nTake:\n\n```\n2x + 5 = 17\n```\n\nSuppose the model returns:\n\n```\nx = 6\n```\n\nThe application can substitute `6`\n\nback into the equation.\n\n```\n2(6) + 5 = 17\n\n12 + 5 = 17\n\n17 = 17\n```\n\nThat gives another signal that the answer works.\n\nBasic arithmetic can use deterministic code for checks.\n\nA simple comparison might look like this:\n\n```\nfunction verifyBasicArithmetic(expected, modelAnswer) {\n  return Number(expected) === Number(modelAnswer);\n}\n```\n\nMore advanced problems need more advanced verification.\n\nThe main idea stays simple:\n\n**Use AI for explanation and flexible reasoning. Verify with deterministic tools where possible.**\n\nAI does not need to calculate everything.\n\nTake:\n\n```\n25 × 8\n```\n\nJavaScript can solve that perfectly well.\n\n``` js\nconst answer = 25 * 8;\n```\n\nSending every basic multiplication problem to an AI model adds cost and latency without much benefit.\n\nA calculator can route different problems to different systems.\n\nA simplified version might look like this:\n\n```\nfunction chooseSolver(problem) {\n  if (isBasicArithmetic(problem)) {\n    return \"local\";\n  }\n\n  return \"ai\";\n}\n```\n\nSimple arithmetic can use local code.\n\nMore complex questions can use the AI layer.\n\nA larger system could also use dedicated math libraries for symbolic work.\n\nDifferent tools can handle different jobs.\n\nThere is no good reason to force every problem through one solver.\n\nNatural-language math questions create a good use case for AI.\n\nTake this:\n\n```\nA train travels 240 kilometers in 3 hours.\nWhat is its average speed?\n```\n\nA traditional calculator first needs to extract:\n\n```\ndistance = 240 km\ntime = 3 hours\n```\n\nThen it needs to identify the formula:\n\n```\nspeed = distance ÷ time\n```\n\nThen it calculates:\n\n```\n240 ÷ 3 = 80\n```\n\nAn AI model can understand the sentence and produce those steps together.\n\nA structured response might look like this:\n\n```\n{\n  \"finalAnswer\": \"\\\\(80\\\\text{ km/h}\\\\)\",\n  \"steps\": [\n    {\n      \"explanation\": \"Use the average speed formula.\",\n      \"math\": \"\\\\[\\\\text{speed} = \\\\frac{\\\\text{distance}}{\\\\text{time}}\\\\]\"\n    },\n    {\n      \"explanation\": \"Insert the values.\",\n      \"math\": \"\\\\[\\\\text{speed} = \\\\frac{240}{3}\\\\]\"\n    },\n    {\n      \"explanation\": \"Calculate the result.\",\n      \"math\": \"\\\\[\\\\text{speed} = 80\\\\text{ km/h}\\\\]\"\n    }\n  ]\n}\n```\n\nMathJax can then turn those LaTeX strings into readable equations.\n\nThis moves the project beyond a [normal calculator](https://dev.to/sudo-self/calculator-2n3f).\n\nThe system now has to understand what the user means before solving the calculation.\n\nPeople enter the same problem in different ways.\n\nOne person may type:\n\n```\nsqrt 144\n```\n\nAnother may type:\n\n```\nsquare root of 144\n```\n\nAnother may use:\n\n```\n√144\n```\n\nAll three mean the same thing.\n\nInput processing can clean some common formatting before sending the request to a solver.\n\nA basic example looks like this:\n\n```\nfunction normalizeInput(input) {\n  return input\n    .trim()\n    .replace(/\\s+/g, \" \");\n}\n```\n\nReal math normalization needs more care.\n\nChanging mathematical input too aggressively can change its meaning.\n\nI prefer conservative cleanup and let the solver interpret the actual expression.\n\nA solver should not invent an answer when the input does not make sense.\n\nTake:\n\n```\n5 + × 9\n```\n\nThe application should return a clear error.\n\nFor example:\n\n```\n{\n  \"status\": \"error\",\n  \"message\": \"I could not read this expression clearly.\"\n}\n```\n\nThat works better than showing a confident but unreliable result.\n\nThe same rule applies when the AI response does not match the expected JSON structure.\n\nThe application should reject malformed output instead of trying to guess what the model meant.\n\nA public calculator needs request limits.\n\nWithout them, someone could submit a huge block of unrelated text.\n\nEmpty input should fail before reaching the model.\n\n```\nif (!problem.trim()) {\n  return error(\"Enter a math problem first.\");\n}\n```\n\nLong input can also have a limit.\n\n```\nif (problem.length > MAX_PROBLEM_LENGTH) {\n  return error(\"The problem is too long.\");\n}\n```\n\nThe output can have limits too.\n\nA solution with 40 tiny steps often makes the problem harder to follow.\n\nThe goal is not to generate the longest explanation.\n\nThe goal is to show enough work for someone to understand the calculation.\n\nA correct answer can still feel difficult to use.\n\nI wanted the solution to have a clear order:\n\n```\nProblem\n↓\nFinal Answer\n↓\nStep-by-Step Work\n```\n\nEach equation needs enough room.\n\nThe explanation should stay short.\n\nImportant operations should stand out.\n\nComplex fractions and equations should remain readable on smaller screens.\n\nThe user should also be able to enter another problem without reloading the entire page.\n\nThe AI model handles the reasoning.\n\nMathJax handles the notation.\n\nThe interface still decides whether the final experience feels easy to follow.\n\nI built a working version around these ideas.\n\nThe ** Step by Step Math Calculator** uses AI to help solve different types of math questions and explain the work behind the answer.\n\nThe important part for me was not just showing a result.\n\nI wanted the calculator to turn the solution into readable steps and properly formatted mathematical expressions.\n\nThat required much more than sending a prompt to an AI model.\n\nThe main pieces now look like this:\n\n```\n┌───────────────────────────┐\n│        User Input         │\n└─────────────┬─────────────┘\n              │\n              ▼\n┌───────────────────────────┐\n│      Input Processing     │\n└─────────────┬─────────────┘\n              │\n              ▼\n┌───────────────────────────┐\n│       Solver Router       │\n└────────┬───────────┬──────┘\n         │           │\n         ▼           ▼\n┌──────────────┐ ┌──────────────┐\n│  Local Math  │ │   AI Model   │\n└───────┬──────┘ └───────┬──────┘\n        │                │\n        └────────┬───────┘\n                 │\n                 ▼\n┌───────────────────────────┐\n│       Verification        │\n└─────────────┬─────────────┘\n              │\n              ▼\n┌───────────────────────────┐\n│      Structured JSON      │\n└─────────────┬─────────────┘\n              │\n              ▼\n┌───────────────────────────┐\n│       LaTeX Output        │\n└─────────────┬─────────────┘\n              │\n              ▼\n┌───────────────────────────┐\n│          MathJax          │\n└─────────────┬─────────────┘\n              │\n              ▼\n┌───────────────────────────┐\n│    Step-by-Step Result    │\n└───────────────────────────┘\n```\n\nThis separation also makes the project easier to change.\n\nA different AI model can replace the current one.\n\nA stronger math engine can handle more deterministic calculations.\n\nThe frontend does not need to know how every solver works.\n\nMathJax only needs valid LaTeX.\n\nEach layer can change without rebuilding the whole project.\n\nAt first, the obvious challenge looked like solving the math.\n\nThat turned out to be only one part.\n\nThe harder product problem involved moving from:\n\n```\ninput → answer\n```\n\nto:\n\n```\ninput\n  ↓\nunderstand\n  ↓\nsolve\n  ↓\nverify\n  ↓\nexplain\n  ↓\nformat\n  ↓\nrender\n```\n\nAI helps with understanding and explaining.\n\nNormal code handles security and application logic.\n\nDeterministic math can verify some results.\n\nLaTeX provides a standard format for mathematical expressions.\n\nMathJax makes those expressions readable inside the browser.\n\nThat combination works much better than asking one tool to handle everything.\n\nI do not need an AI model to tell me that:\n\n```\n2 + 2 = 4\n```\n\nThe interesting cases look more like this:\n\n```\nA shop reduces a $120 item by 15%.\nSales tax of 5% applies after the discount.\nWhat is the final price?\n```\n\nThe calculator has to understand the order of operations in the real-world problem.\n\nIt needs to perform the calculations.\n\nIt needs to explain each step.\n\nIt needs to format percentages and equations.\n\nIt needs to display the result clearly.\n\nThat is where a [step-by-step calculator](https://math.techgrapple.com/) becomes much more interesting than `eval()`\n\n.", "url": "https://wpnews.pro/news/beyond-eval-how-i-built-a-step-by-step-math-calculator-that-explains-its-work-ai", "canonical_source": "https://dev.to/md_zoheb_8386785d6a92cfa2/beyond-eval-how-i-built-a-step-by-step-math-calculator-that-explains-its-work-with-ai-27f7", "published_at": "2026-09-04 02:10:03+00:00", "updated_at": "2026-09-04 02:23:18.304753+00:00", "lang": "en", "topics": ["artificial-intelligence", "ai-tools", "developer-tools"], "entities": [], "alternates": {"html": "https://wpnews.pro/news/beyond-eval-how-i-built-a-step-by-step-math-calculator-that-explains-its-work-ai", "markdown": "https://wpnews.pro/news/beyond-eval-how-i-built-a-step-by-step-math-calculator-that-explains-its-work-ai.md", "text": "https://wpnews.pro/news/beyond-eval-how-i-built-a-step-by-step-math-calculator-that-explains-its-work-ai.txt", "jsonld": "https://wpnews.pro/news/beyond-eval-how-i-built-a-step-by-step-math-calculator-that-explains-its-work-ai.jsonld"}}