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

polynomial

v2.0.0

Published

Parse and compute univariate polynomials over real, rational, complex, quaternion, or modular fields

Readme

Polynomial.js

NPM Package MIT license

Polynomial.js is a TypeScript library for parsing and computing univariate polynomials. It supports real, rational, complex, quaternion, modular, and custom coefficient fields.

The library provides immutable arithmetic operations, derivatives, integrals, Euclidean division, greatest common divisors, reciprocal polynomials, and Horner evaluation. It does not calculate roots, but it can construct a polynomial from known roots.

Installation

npm install polynomial

Polynomial.js requires Node.js 20 or newer when used in Node.js.

Quick Start

import Polynomial from 'polynomial';

Polynomial.setField('R');

const polynomial = Polynomial.fromRoots([1, 2, 3]);

console.log(polynomial.toString());          // x^3-6x^2+11x-6
console.log(polynomial.eval(2));             // 0
console.log(polynomial.derive().toString()); // 3x^2-12x+11

Every polynomial is an instance of the Polynomial class and must be constructed with new. Arithmetic methods return new instances and do not mutate the receiver.

const left = new Polynomial('3x^2');
const sum = left.add('-x^2');

console.log(left.toString()); // 3x^2
console.log(sum.toString());  // 2x^2

CommonJS is supported as well:

const Polynomial = require('polynomial');

Inputs

The constructor and arithmetic methods accept polynomial strings, numbers, coefficient arrays, coefficient maps, and other Polynomial instances.

new Polynomial('23x^4+98x^2+4');
new Polynomial(55);
new Polynomial([1, 2, 3]);       // 3x^2+2x+1
new Polynomial({ 3: 4, 5: 9 });  // 9x^5+4x^3

String exponents must be non-negative integers. Whitespace is ignored. Coefficients may contain multiplication and division, while nested polynomial expressions and parentheses are not parsed.

new Polynomial('2 * 3x^2 + 4/5x - 1');

The selected field parses each coefficient, enabling field-specific forms such as fractions, repeating decimals, and complex numbers.

Polynomial.setField('Q');
console.log(new Polynomial('5/3x^3+4/3x').toString());

Polynomial.setField('C');
console.log(new Polynomial('23ix^4+98x^2+i').toString());

Coefficient Fields

The built-in fields are:

| Name | Coefficients | Implementation | | --- | --- | --- | | R | Real numbers | JavaScript numbers | | Q | Rational numbers | Fraction.js | | C | Complex numbers | Complex.js | | H | Quaternions | Quaternion.js | | Zp | Integers modulo p | Built in, for example Z7 |

Polynomial.setField() selects the default field for future instances. Each instance captures that field when it is constructed, so changing the default does not alter existing polynomials or their subsequent operations.

Polynomial.setField('Q');
const rational = new Polynomial('1/3x');

Polynomial.setField('R');
console.log(rational.add('1/3x').toString()); // 0.(6)x

Division in Zp requires the divisor to have a multiplicative inverse. Use a prime modulus when all non-zero coefficients must be invertible.

Custom Fields

A custom field can be installed as the default with setField() or passed directly to the constructor. Passing it to the constructor avoids shared configuration and keeps the field local to that polynomial and all results derived from it.

import Polynomial, { type PolynomialField } from 'polynomial';

const field: PolynomialField<number> = {
  add: (left, right) => left + Number(right),
  sub: (left, right) => left - Number(right),
  mul: (left, right) => left * Number(right),
  div: (left, right) => left / Number(right),
  parse: value => Number(value),
  empty: value => value === undefined || value === 0,
  pow: (base, exponent) => base ** exponent,
  equals: (left, right) => left === Number(right),
  characteristic: 0,
  magnitude: value => Math.abs(value),
  sqrt: value => value < 0 ? null : Math.sqrt(value),
};

const polynomial = new Polynomial('x^2+2x+1', field);

API

Construction and Configuration

  • new Polynomial(input?, field?) creates a polynomial.
  • Polynomial.fromRoots(roots, field?) creates a monic polynomial with the given roots.
  • Polynomial.quotient(modulus, field?) creates the quotient ring defined by a non-constant modulus polynomial.
  • Polynomial.enumerate(maxDegree, maxElements?) or Polynomial.enumerate(maxDegree, field, maxElements?) enumerates polynomials over a finite prime field.
  • Polynomial.cyclicCodeGenerators(length, dimension, maxGenerators?) or Polynomial.cyclicCodeGenerators(length, dimension, field, maxGenerators?) finds all generator polynomials for a cyclic code.
  • Polynomial.setField(field) selects R, Q, C, H, Zp, or a custom field as the default for future instances.

Arithmetic

  • add(value) returns the sum.
  • sub(value) returns the difference.
  • mul(value) returns the product.
  • addmul(left, right) adds the product of two values.
  • div(value) returns the quotient of polynomial long division.
  • mod(value) returns the remainder of polynomial long division.
  • gcd(value) returns the monic greatest common divisor.
  • lcm(value) returns the monic least common multiple.
  • isDivisibleBy(value) reports whether polynomial division has zero remainder.
  • factor() returns the leading unit followed by monic irreducible factors with multiplicity.
  • isIrreducible() reports whether a positive-degree polynomial is irreducible.
  • cyclicCodeBasis(length) returns the shifted basis generated by a divisor of $x^n-1$.
  • compare(value) compares finite-field polynomials in coefficient order.
  • successor() returns the next polynomial in that order.
  • pow(exponent) raises the polynomial to a non-negative integer power.
  • neg() negates every coefficient.
  • reciprocal() reverses the coefficient order relative to the degree.
  • monic() divides every coefficient by the leading coefficient.
  • dispersion(maxShift?) returns the greatest non-negative integer k for which gcd(p(x), p(x+k)) is non-constant.
  • sqrt() returns a polynomial g satisfying g² = p, or null when no polynomial square root exists.

For R, Q, and C, dispersion() derives a finite search bound from the coefficients. A custom field can provide magnitude() and an optional characteristic to enable the same behavior. Otherwise, pass an explicit non-negative maxShift. Non-constant polynomials over a field with positive characteristic have infinite dispersion because shifts by multiples of the characteristic leave the polynomial unchanged.

Polynomial.setField('Q');

const polynomial = new Polynomial('x^3-7x^2+10x'); // roots: 0, 2, 5
console.log(polynomial.dispersion());               // 5
console.log(polynomial.dispersion(4));              // 3

sqrt() uses the root with the principal leading coefficient. Its negation is the second square root. Exact roots are supported over Q and prime fields, while R also permits irrational coefficients and C uses the principal complex coefficient root. Custom fields must provide sqrt(value). Quaternion coefficients are not supported because the coefficient recurrence assumes commutative multiplication.

const square = new Polynomial('9x^4+6x^3-11x^2-4x+4');
const root = square.sqrt();

console.log(root?.toString());           // 3x^2+x-2
console.log(root?.mul(root).toString()); // 9x^4+6x^3-11x^2-4x+4

Calculus and Evaluation

  • derive(order = 1) returns the requested derivative.
  • integrate(order = 1) returns the requested antiderivative with zero integration constants.
  • eval(value) evaluates the polynomial using Horner's method.
  • compose(value) substitutes a polynomial for the indeterminate using Horner's method.
  • result(value) is a deprecated alias for eval(value).
const polynomial = new Polynomial('2x^3-3x+5');
console.log(polynomial.compose('x^2+1').toString()); // 2x^6+6x^4+3x^2+4

Quotient Rings

Polynomial.quotient(modulus, field?) constructs $K[x]/(m)$. Every element is reduced to its canonical representative of degree less than modulus.degree(). A ring created from an existing polynomial retains that polynomial's coefficient field.

Polynomial.setField('Z2');

const ring = Polynomial.quotient('x^3+x+1');
const alpha = ring.create('x');

console.log(alpha.pow(3).toString());    // x+1
console.log(alpha.pow(7).toString());    // 1
console.log(alpha.inverse().toString()); // x^2+1

The ring provides create(value), zero(), one(), and its monic modulus. evaluate(polynomial, value) evaluates a polynomial at a residue class using Horner's method, while isRoot(polynomial, value) tests whether that value is a root. Residue classes provide add, sub, mul, div, neg, pow, inverse, equals, and isZero. Division and inversion throw RangeError when the divisor is not a unit. Residues from different quotient-ring instances cannot be combined.

Polynomial.setField('Z2');

const ring = Polynomial.quotient('x^3+x+1');
const alpha = ring.create('x');

console.log(ring.evaluate('x^2+x+1', alpha).toString()); // x^2+x+1
console.log(ring.isRoot('x^3+x+1', alpha));              // true

Unlike Polynomial.eval(), which returns a coefficient-field value, ring.evaluate() returns a residue class. Evaluation is defined for every quotient ring and does not require the modulus to be irreducible. Values already belonging to another quotient-ring instance are rejected.

When the coefficient field is Zp and the modulus is irreducible, the quotient is the finite field $\text{GF}(p^n)$. isField() checks this condition, and order() returns $p^n$. The ring can enumerate its elements(), primitiveElements(), and primitivePolynomials(). A residue class provides additiveOrder(), additiveSubgroup(), multiplicativeOrder(), multiplicativeSubgroup(), isPrimitive(), and minimalPolynomial().

Polynomial.setField('Z2');

const field = Polynomial.quotient('x^4+x+1');
const alpha = field.create('x');
const beta = alpha.pow(5);

console.log(field.order());                        // 16
console.log(alpha.multiplicativeOrder());          // 15
console.log(alpha.isPrimitive());                  // true
console.log(beta.multiplicativeSubgroup().map(String));
// ['1', 'x^2+x', 'x^2+x+1']
console.log(beta.minimalPolynomial().toString()); // x^2+x+1
console.log(field.primitivePolynomials().map(String));
// ['x^4+x+1', 'x^4+x^3+1']

primitivePolynomials() returns the distinct minimal polynomials of the primitive elements, ordered by finite-field coefficient order. Frobenius conjugates are deduplicated, so each primitive polynomial occurs exactly once.

The subgroup methods list the identity first, followed by successive multiples or powers of the residue. Their optional limit defaults to one million elements. elements(maxElements?), primitiveElements(maxElements?), and primitivePolynomials(maxElements?) use the same default and throw RangeError before enumeration if the field is larger. Multiplicative operations and minimal polynomials require an irreducible modulus; ordinary quotient-ring arithmetic does not.

Finite-Field Factorization

factor() and isIrreducible() operate over prime coefficient fields Zp. Factorization uses square-free decomposition, Frobenius roots for inseparable polynomials, and Berlekamp's algorithm. Repeated factors occur repeatedly in the returned array.

Polynomial.setField('Z2');

const polynomial = new Polynomial('x^5+x^2+x+1');
console.log(polynomial.factor().map(String));
// ['x+1', 'x+1', 'x^3+x+1']

For a non-monic polynomial, the leading unit is the first factor, so multiplying all returned factors reconstructs the input. The factorization of 1 is empty, while factoring the zero polynomial throws RangeError. Fields of characteristic zero and composite modular rings are rejected.

Cyclic Codes

If $g$ divides $x^n-1$ over a prime field, g.cyclicCodeBasis(n) returns the standard basis $g,xg,\ldots,x^{k-1}g$, where $k=n-\deg g$.

Polynomial.setField('Z2');

const generator = new Polynomial('x^4+x^3+x^2+1');
console.log(generator.cyclicCodeBasis(7).map(String));
// ['x^4+x^3+x^2+1', 'x^5+x^4+x^3+x', 'x^6+x^5+x^4+x^2']

The generator is normalized to monic form. Invalid lengths, the zero polynomial, and generators that do not divide $x^n-1$ are rejected.

Polynomial.cyclicCodeGenerators(n, k) returns every monic divisor of $x^n-1$ having degree $n-k$. Each result therefore generates a cyclic $[n,k]$ code and can be passed to cyclicCodeBasis(n).

Polynomial.setField('Z2');

const generators = Polynomial.cyclicCodeGenerators(7, 4);
console.log(generators.map(String));
// ['x^3+x^2+1', 'x^3+x+1']

console.log(generators[0].cyclicCodeBasis(7).length); // 4

Repeated irreducible factors are retained when the characteristic divides the code length. Dimensions from zero through $n$ are accepted: $k=0$ returns $x^n-1$, while $k=n$ returns $1$. An empty array means that no divisor has the required degree. The optional result limit defaults to one million generators.

Finite-Field Enumeration

compare() and successor() use base-$p$ coefficient order with the constant coefficient as the least significant digit. Polynomial.enumerate(d) returns all $p^{d+1}$ polynomials of degree at most $d$ in that order.

Polynomial.setField('Z2');

console.log(Polynomial.enumerate(1).map(String));
// ['0', '1', 'x', 'x+1']

console.log(new Polynomial('x+1').successor().toString()); // x^2

Enumeration defaults to at most one million results. Pass the limit as the second argument when using the active field, or as the third argument when providing a custom field.

Inspection and Formatting

  • degree() returns the polynomial degree, or -Infinity for the zero polynomial.
  • lc() returns the leading coefficient, or undefined for the zero polynomial.
  • lm() returns the leading monomial.
  • equals(value) compares normalized coefficients in the current field.
  • isZero() reports whether the polynomial is zero.
  • isMonic() reports whether the leading coefficient is one.
  • toArray(width?) returns coefficients in ascending exponent order, optionally padded with zeros.
  • clone() returns an independent polynomial with the same coefficients and field.
  • toString() returns the plain-text representation.
  • toLatex() returns a LaTeX representation.
  • toHorner() returns a Horner-scheme representation.
  • coeff exposes the coefficient map indexed by exponent.
const polynomial = new Polynomial('23x^4+98x^2+4');

console.log(polynomial.coeff[4]); // 23
console.log(polynomial.degree()); // 4
console.log(polynomial.toArray()); // [4, 0, 98, 0, 23]

Division Trace

Set Polynomial.trace to true before division to retain the subtracted terms and final remainder. The property is replaced with an array of polynomial instances.

Polynomial.trace = true;

new Polynomial('x^4+3x^3+2x^2+6x').div('x+3');
console.log(Polynomial.trace.map(step => step.toString()));
// ['x^4+3x^3', '2x^2+6x', '0']

Polynomial.trace = null;

Browser Usage

The browser builds include all built-in coefficient implementations. No separate Fraction.js, Complex.js, or Quaternion.js scripts are required.

Use the global IIFE build directly:

<script src="https://unpkg.com/[email protected]/dist/polynomial.min.js"></script>
<script>
  Polynomial.setField('C');
  console.log(new Polynomial('x-i').mul('x+i').toString());
</script>

Or import the standalone browser ES module:

import Polynomial from 'https://unpkg.com/[email protected]/dist/polynomial.min.mjs';

AMD loaders receive the class as an anonymous module from polynomial.min.js.

TypeScript

The package ships declarations for ESM and CommonJS. ESM exposes the class as both the default and named Polynomial export, together with BuiltInField, PolynomialField, CoefficientMap, PolynomialInput, PolynomialQuotientRing, PolynomialResidue, and PolynomialResidueInput types.

CommonJS namespace aliases are available as Polynomial.FieldName, Polynomial.Field<C>, Polynomial.Coefficients<C>, Polynomial.Input<C>, Polynomial.QuotientRing<C>, Polynomial.Residue<C>, and Polynomial.ResidueInput<C>.

Errors

Malformed polynomial syntax throws SyntaxError. Invalid fields and exponents, division by zero, and non-invertible modular coefficients throw RangeError or TypeError as appropriate.

Development

npm install
npm test

npm test performs a strict TypeScript build, checks ESM and CommonJS declaration consumers, and runs the Node.js and standalone browser tests.

License

Copyright (c) 2026 Robert Eisele

Licensed under the MIT license.