npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

figurate

v1.0.0

Published

Exact BigInt arithmetic for figurate (polygonal) numbers: forward evaluation, membership, index recovery, and iterators for triangular, pentagonal, generalized pentagonal, and every s-gonal family.

Readme

figurate

Exact arithmetic for figurate (polygonal) numbers over BigInt: evaluate, test membership, recover indices, and iterate — for triangular, pentagonal, generalized pentagonal, and every s-gonal family, at any magnitude.

npm install figurate
import {
  triangular, isTriangular, triangularIndex,
  pentagonal, pentagonalIndex,
  polygonal, isPolygonal, polygonalIndex,
  generalizedPentagonalNumbers,
} from "figurate";

triangular(100);                  // 5050n
isTriangular(5050n);              // true
triangularIndex(5050n);           // 100n
pentagonal(10n ** 30n);           // 1499999999999999999999999999999500000000000000000000000000000n
pentagonalIndex(9223372036854775807n); // null — 2^63 - 1 is not pentagonal
polygonal(7, 10);                 // 235n — the 10th heptagonal number
polygonalIndex(7, 235n);          // 10n
[...generalizedPentagonalNumbers({ count: 8 })];
// [0n, 1n, 2n, 5n, 7n, 12n, 15n, 22n]

Zero runtime dependencies. ESM, TypeScript declarations, Node >= 18.

Why this package

Most figurate-number packages generate sequences with float arithmetic and stop there. figurate treats the s-gonal numbers as one algebraic object:

  • One general construction. Everything is P(s, n) = ((s-2)n² - (s-4)n)/2. Triangular is s = 3, square is s = 4, pentagonal is s = 5; the named APIs are specializations, not separate implementations.
  • Exact at any magnitude. All arithmetic is BigInt. number inputs are accepted as a convenience but rejected with a RangeError when they are fractional or outside the safe-integer range — never silently rounded.
  • Inverses, not just generation. Membership and index recovery solve the quadratic exactly: the discriminant (s-4)² + 8(s-2)x must be a perfect square (checked with an exact Newton integer square root) and the root must land on an integer index. Quadratic-residue tables refute most non-members without computing a square root at all.
  • Stated boundary semantics. P(s, 0) = 0 and P(s, 1) = 1 are members of every family; negative values are members of none; indices are always >= 0 except the signed generalized-pentagonal index. Nothing here pretends the figurate numbers are closed under ordinary arithmetic — sums and products of members are generally not members, so the API exposes evaluation, inversion, and iteration rather than fake "operations".

API

All functions accept bigint or safe-integer number and return bigint. Invalid domains throw RangeError; wrong types throw TypeError.

General s-gonal (s ≥ 3)

| Function | Meaning | | --- | --- | | polygonal(s, n) | n-th s-gonal number, n >= 0 | | isPolygonal(s, x) | is x an s-gonal number? | | polygonalIndex(s, x) | the n with polygonal(s, n) === x, else null | | polygonalFloorIndex(s, x) | largest n with polygonal(s, n) <= x (x >= 0) — also the count of positive members <= x | | polygonalNumbers(s, { start?, count?, upTo? }) | generator; additive recurrence, one addition per step |

Named families

triangular, isTriangular, triangularIndex, triangularFloorIndex, triangularNumbers — and the same five for pentagonal. These delegate to the general construction with s fixed.

Generalized pentagonal (Euler)

g(k) = k(3k-1)/2 over all integers k, the exponents of Euler's pentagonal number theorem (OEIS A001318):

| Function | Meaning | | --- | --- | | generalizedPentagonal(k) | k may be negative, zero, or positive | | isGeneralizedPentagonal(x) | membership | | generalizedPentagonalIndex(x) | the unique signed k, else null | | generalizedPentagonalNumbers({ start?, count?, upTo? }) | ascending order 0, 1, 2, 5, 7, 12, 15, … (k = 0, 1, -1, 2, -2, …); start is the position in this order |

k > 0 recovers exactly the ordinary pentagonal numbers; the map is injective over all of ℤ, so the signed index is unique.

Integer square root utilities

| Function | Meaning | | --- | --- | | isqrt(x) | floor(sqrt(x)), exact for any x >= 0 | | sqrtExact(x) | the exact root if x is a perfect square, else null | | isPerfectSquare(x) | boolean form of the above |

Generator options

start (first index / position, default 0), count (maximum yields), upTo (inclusive value bound). With neither count nor upTo the generators are infinite — bound them before spreading.

Semantics worth knowing

  • Index origin is 0: polygonal(s, 0) === 0n. Prefer { start: 1 } if you want the classical 1, 3, 6, 10, … without the leading zero.
  • polygonalIndex returns null for non-members (including all negatives); it throws only for domain errors (s < 3, bad input types).
  • A perfect-square discriminant is necessary but not sufficient: for s = 5, x = 2 the discriminant is 49 = 7² yet 2 is not pentagonal (it is generalized pentagonal, k = -1). The divisibility check catches this; tests pin it.

Performance

Measured with npm run bench (Node 26, Apple Silicon; medians of 5 rounds):

  • Membership on random 128-bit non-members: ~126 ns/op — the residue tables (mod 64 and mod 45045) refute ~99% of non-squares before any square root, about 4.9× faster than an unconditional-isqrt implementation of the same discriminant test.
  • Index recovery on ~200-bit members: ~0.8 µs/op, exact round trip.
  • isqrt: ~190 ns at 64 bits, ~2.3 µs at 1024 bits, ~0.5 ms at 32768 bits.
  • Sequence generation streams by additive recurrence (one BigInt addition per step); at small magnitudes this is a modest ~1.2× over per-index closed-form evaluation, and the gap grows with operand size.

Numbers vary by machine; the benchmark script ships in bench/ and compares only against direct formulas running in the same harness.

Design

Formulas, domain proofs, invariants, complexity, and rejected alternatives are in DESIGN.md. The release checklist lives in docs/canonicality.md.

License

MIT © Xyra Sinclair