# rpncalc/v1 — RPN calculator module

Evaluates arithmetic expressions written in Reverse Polish Notation (postfix).
Tokens are whitespace-separated; each token is either a number or an operator/
function that pops its operands off a stack and pushes the result.

## Endpoint

### `POST /v1/rpncalc/rpn`

**Request**

```json
{ "expr": "3 4 + 2 *" }
```

`format` is optional and controls how the result is rendered: `dec` (default),
`hex`, `bin`, or `oct`.

```json
{ "expr": "3 4 + 2 *", "format": "hex" }
```

**Response**

For `format: "dec"` (or omitted), `result` is a JSON number:

```json
{ "result": 14 }
```

For `hex` / `bin` / `oct`, `result` is a prefixed string (`0x`, `0b`, `0o`;
negative values are rendered as `-0x2`, etc.):

```json
{ "result": "0xe" }
```

Non-`dec` formats require the result to be a whole number — if the expression
produces a fractional value, the request fails with HTTP 400 rather than
silently truncating.

**Error response** (HTTP 400)

```json
{ "error": "division by zero" }
```

```json
{ "error": "cannot format non-integer result 1.5 as hex" }
```

## Number literals

- Decimal: `3`, `1.5`, `-7`
- Hex: `0xFF`
- Binary: `0b1010`
- Octal: `0o17`

## Supported operators & functions

Stack order for binary ops is `a b op` (i.e. `a` was pushed first, `b` second).

### Basic arithmetic
| Token | Meaning |
|---|---|
| `+` | `a + b` |
| `-` | `a - b` |
| `*` | `a * b` |
| `/` | `a / b` (error on `b == 0`) |

### Exponentiation & modulo
| Token | Meaning |
|---|---|
| `^`, `pow` | `a ^ b` |
| `%`, `mod` | `a mod b` (error on `b == 0`) |

### Roots
| Token | Meaning |
|---|---|
| `sqrt` | `√a` (error if `a < 0`) |
| `cbrt` | cube root of `a` |
| `nroot` | `x n nroot` → `x^(1/n)` (error if `n == 0`) |

### Trigonometry (radians)
| Token | Meaning |
|---|---|
| `sin`, `cos`, `tan` | |
| `asin`, `acos`, `atan` | |
| `atan2` | `y x atan2` |

### Hyperbolic
| Token | Meaning |
|---|---|
| `sinh`, `cosh`, `tanh` | |

### Logarithms & exponentials
| Token | Meaning |
|---|---|
| `ln` | natural log (error if `a <= 0`) |
| `log2`, `log10` | (error if `a <= 0`) |
| `logn` | `x base logn` → `log_base(x)` (errors on invalid base) |
| `exp` | `e^a` |
| `exp2` | `2^a` |

### Angle conversion
| Token | Meaning |
|---|---|
| `todeg` | radians → degrees |
| `torad` | degrees → radians |

### Rounding
| Token | Meaning |
|---|---|
| `ceil`, `floor`, `round`, `trunc` | |

### Misc math
| Token | Meaning |
|---|---|
| `abs` | absolute value |
| `neg` | negation |
| `sign` | `-1`, `0`, or `1` |
| `hypot` | `a b hypot` → `√(a²+b²)` |
| `fact` | factorial (non-negative integer only) |

### Bitwise (operands truncated to `int64`)
| Token | Meaning |
|---|---|
| `&`, `and` | AND |
| `\|`, `or` | OR |
| `xor` | XOR |
| `~`, `not` | bitwise NOT |
| `<<`, `shl` | shift left |
| `>>`, `shr` | shift right |
| `popcount` | count of set bits |

### Constants
| Token | Value |
|---|---|
| `pi` | π |
| `e` | Euler's number |
| `phi` | golden ratio |
| `inf` | +∞ |

## Errors

`Evaluate` returns an error (surfaced as HTTP 400) for:
- not enough operands for an operator
- leftover values on the stack (expression doesn't reduce to one result)
- unknown tokens
- domain errors: division/modulo by zero, `sqrt`/`ln`/`log2`/`log10` of invalid input, invalid `logn` base, non-integer/negative `fact`

## Examples

```bash
curl -s -X POST http://localhost:8080/v1/rpncalc/rpn \
  -H 'Content-Type: application/json' \
  -d '{"expr": "3 4 + 2 *"}'
# {"result":14}

curl -s -X POST http://localhost:8080/v1/rpncalc/rpn \
  -H 'Content-Type: application/json' \
  -d '{"expr": "27 3 nroot"}'
# {"result":3}

curl -s -X POST http://localhost:8080/v1/rpncalc/rpn \
  -H 'Content-Type: application/json' \
  -d '{"expr": "0xFF 0x0F and"}'
# {"result":15}

curl -s -X POST http://localhost:8080/v1/rpncalc/rpn \
  -H 'Content-Type: application/json' \
  -d '{"expr": "3 4 + 2 *", "format": "hex"}'
# {"result":"0xe"}
```

## Files

- `rpncalc.go` — module wiring (routes, HTTP handler)
- `rpn.go` — expression evaluator
- `rpn_test.go` — test cases covering every operator
