🧮 Scientific Calculator

📐 Angle mode

Controls input units for sin/cos/tan and output units for asin/acos/atan/atan2.

📝 Expression

Results update as you type. Press = to record the current evaluation to history.

🎹 Quick insert

📤 Result

🔁 RPN form

Postfix (Reverse Polish) form — operands first, then the operator. Function calls are annotated with their argument count (e.g. max:3).

🕒 History (last 10)

No evaluations yet. Press = to record one.
  1. {{ entry }}
⚠️

ℹ️ About Scientific Calculator

Scientific calculator with a safe expression parser

Type a mathematical expression — 2 + 3 * sin(pi/4), log(1000) + sqrt(16), 5! — and the tool tokenises it, parses it via the shunting-yard algorithm into Reverse Polish Notation (RPN), and evaluates the RPN with a stack machine. The result is normalised to 15 significant figures to suppress floating-point noise like 0.30000000000000004. The RPN form is displayed alongside the result so you can see exactly how precedence resolved.

Switch between radians and degrees for trigonometric functions. The setting affects forward trig (sin, cos, tan) and inverse trig (asin, acos, atan, atan2) identically.

Security: no eval(), no Function(...)

Many online "scientific calculators" pass user input directly to JavaScript's eval() or new Function(). That is dynamic code execution: the expression becomes code. An attacker who controls the input can run anything the host page can run — read cookies, exfiltrate localStorage, call APIs, hijack the page. The same hole exists on the server when PHP eval() is used to "compute" a user-supplied expression.

This tool ships its own tokeniser and parser. The grammar is fixed at compile time: it can only produce numbers, predefined operators, and a closed list of mathematical functions. Identifiers that don't match a known function or constant raise Function "foo" not recognized. The same parser runs in your browser and in the server-side API, because both consume the same compiled TypeScript logic module (scientific-calculator.logic.js) — see the OWASP Code Injection page for why eval() on user input must never appear in production code.

Supported syntax

  • Binary operators: + - * / % (modulo) mod (alias for %) ^ (right-associative power)
  • Unary operators: -x (negation) and +x (no-op)
  • Parentheses for grouping; nesting depth is bounded by the operator stack
  • Trig: sin, cos, tan, asin, acos, atan, atan2(y, x)
  • Logarithms: ln (natural), log (base 10), log2 (base 2)
  • Other functions: exp, sqrt, cbrt, abs, floor, ceil, round
  • Factorial: factorial(5) or postfix 5! (non-negative integers ≤ 170; computed with BigInt internally)
  • Variadic: max(...), min(...) with one or more arguments
  • Constants: pi, e
  • Numbers: decimal (3.14) and scientific notation (1.5e10, 2.5E-3)

How the parser works

The tokeniser scans the input character by character and emits a stream of tokens: number, identifier (function or constant), operator, parenthesis, comma, bang. Scientific notation is recognised inside the number scanner so 1.5e10 becomes a single number token, not three.

The shunting-yard algorithm, originally described by Edsger W. Dijkstra in 1961, converts the infix token stream to postfix (RPN) by shuffling tokens between an output queue and an operator stack. Precedence is fixed: function call > postfix ! > unary -/+ > ^ (right-associative) > * / % mod > + -. Function calls push the function onto the stack; commas commit the current argument and increment the call's arity counter.

The RPN evaluator is a classic stack machine: numbers push, operators pop their arguments and push the result, functions pop their declared arity and push their return value. A well-formed expression leaves exactly one value on the stack at the end.

Worked examples

  • 2 + 3 * 4 → 14 (precedence: multiplication first)
  • (2 + 3) * 4 → 20 (parentheses override)
  • 2^3^2 → 512 (right-associative: evaluated as 2^(3^2))
  • 10 mod 3 → 1 (modulo)
  • sin(pi) → 0 in rad mode
  • sin(90) → 1 in deg mode
  • log(1000) → 3 (base 10)
  • ln(e) → 1
  • 5! → 120 (postfix factorial)
  • atan2(1, 1) → π/4 ≈ 0.785398 in rad mode
  • max(1, 2, 3, 4) → 4

Error handling

The parser raises distinct, actionable errors instead of silently returning NaN:

  • Unexpected token at position N: "..."
  • Function "fooBar" not recognized
  • Missing operand for operator "..."
  • Mismatched parentheses
  • Division by zero
  • sqrt of negative number
  • log of non-positive number
  • Factorial requires non-negative integer ≤ 170

NaN or infinite results raise Result is NaN / Result is infinite. They never leak into the output box. The expression length is capped at 1000 characters to bound parser work.

Use cases

  • Homework check. Verify by-hand answers to algebra, pre-calc, and physics problems.
  • Engineering scratchpad. One-liner with units in your head — 3 * 9.81 * 10^2 — without launching a heavier tool.
  • Programmer math. Mod, floor, ceil, log2, factorial; everything you reach for when sizing data structures or estimating Big-O constants.
  • Trig sanity checks. Toggle rad/deg to confirm your assumptions before plugging values into another tool.
  • Documenting numerical claims. Send the expression instead of the answer — the recipient can paste it back to verify.

Limitations

  • No symbolic algebra. The parser produces numbers, not expressions. sqrt(2) evaluates to 1.41421356237310, not √2.
  • IEEE 754 floats. Results inherit double-precision rounding. Use round/floor/ceil to discretise.
  • Factorial overflow. factorial(171) overflows the double precision range and raises.
  • No variables. Identifiers must be a known function name or constant (pi, e); user-defined names are rejected.
  • No implicit multiplication. 2pi is rejected — write 2*pi.
  • No hex literals. 0xFF raises an error; convert to decimal first.

References

  • Edsger W. Dijkstra, An Algorithm for Translating Mathematical Formulae (Mathematisch Centrum Amsterdam, 1961) — original shunting-yard algorithm.
  • Wikipedia: Shunting-yard algorithm, Reverse Polish notation.
  • OWASP, Code Injection — why eval() on user input is dangerous.
  • ECMA-262, §21 (Math object) — base of the numeric primitives used here.

API Usage Example:

POST /api/tools/math/scientific-calculator
Content-Type: application/json

{
    "expression": "2 + 3 * 4",
    "angleMode": "rad"
}
Ready