Calculator: exponentiation and modulo #3

Open
opened 2026-09-28 11:10:25 +02:00 by clawbot · 0 comments

Part of #2. Independent of the API units.

What. The calculator accepts ^ (also written **) for exponentiation and % for modulo, with the usual precedence, alongside what it does now.

Decisions (reversible, taken by the repo-manager):

  • ^ and ** are one operator. It binds tighter than *, /, % and than a sign on its left, and groups to the right: 2^3^2 is 512, -2^2 is -4, (-2)^2 is 4, 2^-1 is 0.5.
  • % sits with * and /, left to right. The result takes the sign of the divisor, as in Python and most calculators: 7 % 3 is 1, -7 % 3 is 2, 7 % -3 is -2. It works on decimals, exactly: 7.5 % 2 is 1.5, 0.3 % 0.1 is 0. x % 0 is division by zero.
  • A whole-number exponent is computed exactly: 0.1^2 is 0.01, 2^100 - 2^100 + 1 is 1. A fractional exponent is computed in float64: 2^0.5 is 1.4142135623730951. A negative base with a fractional exponent has no real result and gets its own reply. 0^0 is 1; zero to a negative power is division by zero.
  • Bounded work: an exact power whose result would pass a fixed size (for example 4096 bits of numerator plus denominator, estimated before multiplying) is computed in float64 instead; a float result that overflows is refused as too large, as now. A test shows the worst cases that fit in 256 bytes (such as 9^9^9^9^9, ((9^999)^999)^999, 1.0000001^99999) answer promptly.
  • go/parser cannot express this (^ is XOR at the precedence of +, and ** does not parse), and neither the standard library nor the default package list parses exact arithmetic with a power operator. So internal/calc gets a small tokenizer and precedence-climbing parser of its own, still computing with go/constant. Keep the decimal-only number rule (010 is ten; no hex, _ or i), the 256-byte limit, and refusal of everything else. Small and plain: a newcomer follows it in one reading.

Done when:

  • internal/calc tests cover precedence, grouping, signs, every example above, the refusals and the bounded-work cases; the existing tests still pass, changed only where the parser change must change them.
  • bot.Reply's "I only understand arithmetic" sentence and the welcome text mention ^ and %; the no-real-result case has its own sentence.
  • README: the introduction and the Arithmetic design bullet say how to write powers and modulo, with examples. docs/TODO.md Completed Steps gets a line.
  • make check is green.

Model: opus-5-5

Part of https://git.eeqj.de/sneak/simplexcalc/issues/2. Independent of the API units. **What.** The calculator accepts `^` (also written `**`) for exponentiation and `%` for modulo, with the usual precedence, alongside what it does now. **Decisions** (reversible, taken by the repo-manager): - `^` and `**` are one operator. It binds tighter than `*`, `/`, `%` and than a sign on its left, and groups to the right: `2^3^2` is `512`, `-2^2` is `-4`, `(-2)^2` is `4`, `2^-1` is `0.5`. - `%` sits with `*` and `/`, left to right. The result takes the sign of the divisor, as in Python and most calculators: `7 % 3` is `1`, `-7 % 3` is `2`, `7 % -3` is `-2`. It works on decimals, exactly: `7.5 % 2` is `1.5`, `0.3 % 0.1` is `0`. `x % 0` is division by zero. - A whole-number exponent is computed exactly: `0.1^2` is `0.01`, `2^100 - 2^100 + 1` is `1`. A fractional exponent is computed in float64: `2^0.5` is `1.4142135623730951`. A negative base with a fractional exponent has no real result and gets its own reply. `0^0` is `1`; zero to a negative power is division by zero. - Bounded work: an exact power whose result would pass a fixed size (for example 4096 bits of numerator plus denominator, estimated before multiplying) is computed in float64 instead; a float result that overflows is refused as too large, as now. A test shows the worst cases that fit in 256 bytes (such as `9^9^9^9^9`, `((9^999)^999)^999`, `1.0000001^99999`) answer promptly. - `go/parser` cannot express this (`^` is XOR at the precedence of `+`, and `**` does not parse), and neither the standard library nor the default package list parses exact arithmetic with a power operator. So `internal/calc` gets a small tokenizer and precedence-climbing parser of its own, still computing with `go/constant`. Keep the decimal-only number rule (`010` is ten; no hex, `_` or `i`), the 256-byte limit, and refusal of everything else. Small and plain: a newcomer follows it in one reading. **Done when:** - `internal/calc` tests cover precedence, grouping, signs, every example above, the refusals and the bounded-work cases; the existing tests still pass, changed only where the parser change must change them. - `bot.Reply`'s "I only understand arithmetic" sentence and the welcome text mention `^` and `%`; the no-real-result case has its own sentence. - README: the introduction and the Arithmetic design bullet say how to write powers and modulo, with examples. `docs/TODO.md` Completed Steps gets a line. - `make check` is green. Model: opus-5-5
clawbot added a new dependency 2026-09-28 11:10:29 +02:00
clawbot self-assigned this 2026-09-28 11:10:30 +02:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Reference: sneak/simplexcalc#3