Functional Weave
Code in TypeScript

math.pow

base to the power exponent from + - * / only, exact by squaring for whole exponents, identical in every language.

1.0.0 · published 2026-10-03 by charlie · Anterra

Pinned by 16 tests, run in TypeScript, Python and Rust.

What it does

`base` to the power `exponent`, bit-identical in TypeScript, Python and Rust.

- **Whole-number exponents** are done by repeated squaring, so `pow(10, 3)` is exactly `1000` and `pow(-2, 3)` is `-8`. A negative whole exponent is the reciprocal. `exp(3 x ln 10)` would give 999.9999999999998. - **Other exponents** are `exp(exponent x ln(base))`, from `math.exp` and `math.ln`, which use only IEEE-exact operations. The error grows with the size of `exponent x ln(base)`: within a few dozen units in the last place for everyday arguments (cube roots, the sRGB gamma 2.4), which is far below any rounding a caller applies, and identical in every language, which is the point.

For example

  • pow(10, 3) → 1,000 a whole exponent is exact: 10^3 is 1000, not 999.9999999999998
  • pow(2, -2) → 0.25 a negative whole exponent
  • pow(-2, 3) → -8 a negative base with an odd exponent

The function

The same function in TypeScript, Python and Rust, pinned by the same tests. Pick your language; the choice follows you around the registry.

export function pow(base: number, exponent: number): number
basefloatany finite number; negative only with a whole-number exponent
exponentfloatany finite number; 1/3 is a cube root, 2.4 the sRGB gamma
returnsfloatbit-identical in every language

Your code names it in one line, in the file that uses it

import { pow } from "#fune/math.pow@^1";
impl/typescript.ts · 46 lines · open · raw

Imports name this capability’s declared dependencies, which fune builds next to it in your project; each one links to its page.

import { ln } from "./math_ln.ts";  ← from math.ln ^1.0.0 · built alongside by fune
import { exp } from "./math_exp.ts";  ← from math.exp ^1.0.0 · built alongside by fune

// Below this exponent of e the result is smaller than any normal double.
const SMALLEST = -708;
const LARGEST = 709;

/**
 * base^exponent with the same bits in TypeScript, Python and Rust.
 *
 * A whole-number exponent is done by repeated squaring, so 10^3 is exactly
 * 1000 and (-2)^3 is -8, where exp(3 ln 10) would be 999.9999999999998. Any
 * other exponent is exp(exponent * ln(base)) from math.exp and math.ln, which
 * use only operations IEEE 754 defines exactly; Math.pow and ** are the
 * platform's and may differ in the last bit.
 */
export function pow(base: number, exponent: number): number {
  if (typeof base !== "number" || !Number.isFinite(base)) {
    throw new RangeError(`pow needs a finite base, received ${base}`);
  }
  if (typeof exponent !== "number" || !Number.isFinite(exponent)) {
    throw new RangeError(`pow needs a finite exponent, received ${exponent}`);
  }
  if (base === 0) {
    if (exponent < 0) throw new RangeError("zero cannot be raised to a negative power");
    return exponent === 0 ? 1 : 0;
  }
  if (Math.floor(exponent) === exponent) {
    let n = Math.abs(exponent);
    let b = base;
    let result = 1;
    while (n > 0) {
      if (n % 2 === 1) result *= b;
      n = Math.floor(n / 2);
      if (n > 0) b *= b;
    }
    if (exponent < 0) result = 1 / result;
    if (!Number.isFinite(result)) throw new RangeError("pow result is too large to represent");
    return result + 0;
  }
  if (base < 0) throw new RangeError("a negative base needs a whole-number exponent");
  const power = exponent * ln(base);
  if (power > LARGEST) throw new RangeError("pow result is too large to represent");
  if (power < SMALLEST) return 0;
  return exp(power);
}

Install

fune build

With that line in your source, in a TypeScript project (language typescript in fune.project), fune build resolves it and its 2 dependencies, pins them in fune.lock, downloads only the TypeScript package of each, and builds the code above into your project’s .fune/build, one readable file per capability with a header linking back here. Or pin a range in fune.project and build in one step:

fune add math.pow
Download for TypeScript math.pow-1.0.0-typescript.fune · 6,234 bytes sha256 2c7e6862bfeb6ec90479be1c68cec591f0ec09a50d26b8c978b025353a10eac3

The manifest, vectors and README with only the TypeScript implementation. Install it without the registry with fune add ./math.pow-1.0.0-typescript.fune, or fetch it from a terminal with fune pull math.pow@1.0.0:typescript.

The whole function, every language, is one file too: math.pow-1.0.0.fune, 10,336 bytes, sha256 cd57d65c28d5c41529f94f72488bf0eaae5a2fe9c3bc09339de550bc46cd5cc7. It installs into a project of any language.

Customise it in your app

The seams this capability offers. Put a marker directly above a function of your own and fune build wires it into the built code; the package on the registry is not changed, the built file’s header lists it under CUSTOMISED, and fune hooks lists every hook in the project. How hooks work.

before — your function gets the arguments and returns them, changed or not, or throws to refuse the call.

// fune: before math.pow

after — your function gets the result and the arguments, and returns the final result.

// fune: after math.pow

replace — inside this capability’s code only, calls to a dependency go to your function, with the same signature. Other capabilities that use it are unaffected; write in * to replace it everywhere.

// fune: replace math.exp in math.pow
// fune: replace math.ln in math.pow

step — your function runs at a numbered point inside the function’s body, receives the in-scope values it names as parameters, and may return replacements. List the points with fune show math.pow --steps.

// fune: step math.pow after <n|label>

Tests

A version published now needs at least 8 tests for every function, and one that expects the error for each function that throws; the registry refuses it otherwise. fune verify --all runs each case in TypeScript, Python and Rust, and a project runs them again with fune verify. This page lists the cases; it does not run them. The exact JSON is vectors.json.

CaseArgumentsExpected
a whole exponent is exact: 10^3 is 1000, not 999.9999999999998 10, 3 → 1,000
a negative whole exponent 2, -2 → 0.25
a negative base with an odd exponent -2, 3 → -8
a negative base with an even exponent -2, 2 → 4
squaring keeps binary rounding: 1.1^2 1.1, 2 → 1.21
a square root 2, 0.5 → 1.414
a cube root 8, 0.333 → 2
the sRGB gamma exponent 0.5, 2.4 → 0.189
anything to the power 0 is 1 7.5, 0 → 1
zero to the power 0 is 1 0, 0 → 1
Show the other 6 tests
CaseArgumentsExpected
zero to a positive power is 0 0, 2.5 → 0
a result below the smallest normal double is 0 0.5, 2,000.5 → 0
zero to a negative power is an error 0, -1 → error: zero cannot be raised to a negative power
a negative base with a fractional exponent is an error -8, 0.333 → error: a negative base needs a whole-number exponent
an overflowing whole power is an error 10, 400 → error: pow result is too large to represent
an overflowing fractional power is an error 10, 400.5 → error: pow result is too large to represent

More from the author

Edge cases: `0^0` is 1, `0^positive` is 0, `0^negative` is an error. A negative base needs a whole-number exponent (the real answer does not exist otherwise). A result too large for a double is an error; one smaller than the smallest normal double (about 1e-308) is 0.

`**`, `Math.pow`, `math.pow` and `f64::powf` are not used because they come from each platform's maths library, whose last bit may differ.

Files

PathBytes
README.md1,109
impl/python.py1,876
impl/rust.rs2,053
impl/typescript.ts1,779
vectors.json1,605