diff options
| author | Paul Buetow <paul@buetow.org> | 2026-05-24 11:30:52 +0300 |
|---|---|---|
| committer | Paul Buetow <paul@buetow.org> | 2026-05-24 11:30:52 +0300 |
| commit | d718e8d6a942be3701688359e898933cff27c5ee (patch) | |
| tree | de4ff85ffdcb0fb8caebbce2a13b24ec72bbed11 | |
| parent | ebcbe6cc47260ee493764993a9d0939261044c5a (diff) | |
docs: add fast-power.md documenting ** operator
Cover binary exponentiation algorithm, syntax, examples,
** vs ^ comparison, edge cases, and performance notes.
| -rw-r--r-- | docs/fast-power.md | 115 |
1 files changed, 115 insertions, 0 deletions
diff --git a/docs/fast-power.md b/docs/fast-power.md new file mode 100644 index 0000000..5d6a981 --- /dev/null +++ b/docs/fast-power.md @@ -0,0 +1,115 @@ +# Fast Power Operator (`**`) + +The `**` operator computes integer exponentiation using **binary exponentiation** (also known as square-and-multiply). It raises the base (first operand) to the integer power of the exponent (second operand) on the RPN stack. + +## Binary Exponentiation + +Binary exponentiation reduces the number of multiplications from O(n) to O(log n) by exploiting the binary representation of the exponent. + +The algorithm works as follows: + +1. Initialize `result = 1` +2. While the exponent is positive: + - If the exponent is **odd**, multiply `result` by the current `base` + - Square the `base` + - Divide the exponent by 2 (integer division) +3. For negative exponents, compute `1 / (base^|exp|)` + +### Example: 3^13 + +| Step | exp | exp odd? | result | base | +|------|-----|----------|--------|------| +| 0 | 13 | yes | 1 * 3 = 3 | 3 | +| 1 | 6 | no | 3 | 9 | +| 2 | 3 | yes | 3 * 9 = 27 | 81 | +| 3 | 1 | yes | 27 * 81 = 2187 | 6561 | +| 4 | 0 | — | **2187** | — | + +Only 4 multiplications instead of 12. For 10^100, that's ~17 multiplications instead of 99. + +## Syntax + +RPN (Reverse Polish Notation): + +``` +base exponent ** +``` + +Operands are popped in reverse order: `exponent` (top) then `base`, result is `base^exponent`. Pushed back as a unitless (Cool) number. + +## Examples + +### Integer exponent + +``` +2 10 ** → 1024 +``` + +### Negative exponent + +``` +2 -3 ** → 0.125 (i.e., 1/8) +``` + +### Zero exponent + +``` +5 0 ** → 1 +``` + +Any number to the power of 0 is 1 (short-circuited, no multiplication performed). + +### Large exponent + +``` +10 100 ** → 1e+100 +``` + +### Fractional exponent (rejected) + +``` +2 1.5 ** → Error: exponent must be an integer, got 1.5 +``` + +The `**` operator **requires** an integer exponent. Use `^` for fractional exponents. + +## `**` vs `^` + +| Feature | `**` (Fast Power) | `^` (Power) | +|---------|-------------------|-------------| +| Exponent type | Integer only | Any float | +| Algorithm | Binary exponentiation (square-and-multiply) | `math.Pow()` | +| Complexity | O(log n) multiplications | Hardware/logarithm-based | +| Fractional exponents | Rejected with error | Supported | +| Negative exponents | Supported (as `1/base^|n|`) | Supported | +| Zero exponent | Short-circuited → 1 | `math.Pow(base, 0)` → 1 | + +### When to use `**` + +- Exponent is a known integer +- You want a fast, exact integer-power computation +- You want to guard against accidental fractional exponents + +### When to use `^` + +- Exponent may be fractional (e.g., `9 0.5 ^` → 3 for square root) +- Working with arbitrary floating-point exponents +- General-purpose power computation + +## Edge Cases + +| Input | Result | Notes | +|-------|--------|-------| +| `x 0 **` | 1 | Short-circuited; no multiplications | +| `x -n **` | 1/(x^n) | Computed recursively via positive exponent | +| `0 0 **` | 1 | By convention (0^0 = 1) | +| `2 1.5 **` | Error | Fractional exponents not supported | +| `x n **` (n large) | float64 result | Result limited by float64 range; may overflow to Inf | +| `-2 3 **` | -8 | Negative base with integer exponent works correctly | + +## Performance Notes + +- **Time complexity**: O(log |n|) where n is the exponent. An exponent of 100 requires only ~7 loop iterations (vs 99 naive multiplications). +- **Space complexity**: O(1) for positive exponents; O(log |n|) stack depth for negative exponents (recursive call). +- The implementation uses `float64` throughout, so results may lose precision for very large exponents (same limitations as any floating-point computation). +- For the specific case of exponent 0, the function returns 1 immediately without entering the loop. |
