📐 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)
= to record one.
- {{ 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 postfix5!(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 as2^(3^2))10 mod 3→1(modulo)sin(pi)→0in rad modesin(90)→1in deg modelog(1000)→3(base 10)ln(e)→15!→120(postfix factorial)atan2(1, 1)→π/4 ≈ 0.785398in rad modemax(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 to1.41421356237310, not√2. - IEEE 754 floats. Results inherit double-precision rounding. Use
round/floor/ceilto 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.
2piis rejected — write2*pi. - No hex literals.
0xFFraises 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"
}