NAME
Sidef::Types::Number::Polynomial - Polynomial type supporting symbolic manipulation and algebraic operations.
DESCRIPTION
This class implements univariate polynomials with arbitrary-precision coefficients. Polynomials are represented as mathematical expressions in a single variable (x), supporting arithmetic, evaluation, differentiation, root-finding, and algebraic manipulation.
Internally, polynomials are stored as a sparse hash mapping integer exponents to their coefficients (Sidef::Types::Number::Number objects). Terms with a zero coefficient are never stored, making the representation efficient for sparse polynomials with many zero terms.
SYNOPSIS
# Constructors
var a = Polynomial(5) # monomial x^5
var b = Polynomial([1, 2, 3, 4]) # x^3 + 2*x^2 + 3*x + 4
var c = Polynomial(5 => 3, 2 => 10) # 3*x^5 + 10*x^2
var d = Polynomial("x^3 - 2*x + 1") # parsed from string
# Arithmetic
var sum = (b + c) # polynomial addition
var prod = (b * c) # polynomial multiplication
var quot = (b / c) # polynomial division
# Evaluation
say(b.eval(2)) # evaluate at x=2: 26
# Algebraic operations
say(b.derivative) # 3*x^2 + 4*x + 3
say(b.roots) # numerical roots
say(b.gcd(c)) # greatest common divisor
COEFFICIENT ORDER IN ARRAY CONSTRUCTORS
When building a polynomial from an array, coefficients are supplied in descending degree order (highest-degree first):
Polynomial([a_n, a_{n-1}, ..., a_1, a_0])
# represents: a_n*x^n + a_{n-1}*x^{n-1} + ... + a_1*x + a_0
Examples:
Polynomial([1, 2, 3]) # x^2 + 2*x + 3 (NOT 3*x^2 + 2*x + 1)
Polynomial([1, 0, -1]) # x^2 - 1
Polynomial([1, 0, 0, 1]) # x^3 + 1
Individual array elements may also be [exponent, coefficient] pairs to set a coefficient at an explicit degree:
Polynomial([[3, 2], [1, 5]]) # 2*x^3 + 5*x
INHERITS
Inherits methods from Sidef::Types::Number::Number.
CONSTRUCTION
new
Polynomial(n)
Polynomial([c_n, ..., c_1, c_0])
Polynomial("expression")
Polynomial(exp1 => coeff1, exp2 => coeff2, ...)
self.new(value)
Constructs a new Polynomial object. The following calling forms are supported:
- Monomial — a single
Numberargumentn: creates the monomialx^n. -
Polynomial(5) # x^5 Polynomial(0) # x^0 = 1 - Array — a single array-ref argument: coefficients in descending degree order.
-
Polynomial([1, 2, 3]) # x^2 + 2*x + 3Array elements may themselves be
[exponent, coeff]pairs for explicit placement:Polynomial([[2, 1], [0, 3]]) # x^2 + 3 - String — a single string argument: parses an algebraic expression. Supports terms of the form
[±][coefficient[/denominator]*]x[^exponent], as well as fraction syntax(numerator)/(denominator). -
Polynomial("3*x^2 + 2*x + 1") # 3*x^2 + 2*x + 1 Polynomial("x^3 - 5") # x^3 - 5 Polynomial("1/2*x^2 + 3/4") # (1/2)*x^2 + 3/4A string that can't be parsed in full returns the constant polynomial
NaN, rather than raising an error. - Sparse key-value pairs — alternating exponent/coefficient arguments:
-
Polynomial(5 => 3, 2 => 10) # 3*x^5 + 10*x^2 Polynomial(0 => 7) # constant 7Zero coefficients are silently dropped. If the same exponent is given more than once, only the last value for that exponent is kept.
- Instance call with one argument — when called as a method on an existing polynomial, evaluates that polynomial at the given value (equivalent to "eval"):
-
var p = Polynomial([1, 0, -1]) # x^2 - 1 say(p.new(3)) # 3^2 - 1 = 8
Aliases: call
with_value
self.with_value(value)
Creates a new constant polynomial holding just value (equivalent to Polynomial(0 = value)>), discarding the receiver's own terms entirely. Useful in generic code that has a Polynomial in hand and wants to build a plain scalar-valued polynomial of the same type.
var p = Polynomial([1, 2, 3])
say(p.with_value(7)) # 7
ARITHMETIC OPERATIONS
add
a + b
Returns the sum of a and b. When both arguments are polynomials, corresponding coefficients are added. When b is a scalar, it is added to the constant term (x^0 coefficient), inserting it if absent.
say(Polynomial([1, 2]) + Polynomial([3, 4])) # 4*x + 6
Aliases: +
sub
a - b
Returns the difference a - b. When both arguments are polynomials, corresponding coefficients are subtracted. When b is a scalar, it is subtracted from the constant term, inserting a negated term if absent.
say(Polynomial([1, 2, 3]) - Polynomial([0, 1])) # x^2 + x + 3
Aliases: -
mul
a * b
Returns the product of a and b. When both are polynomials, performs full polynomial multiplication (convolution of coefficients): the degree of the result equals deg(a) + deg(b). When b is a scalar, each coefficient is multiplied by b.
say(Polynomial([1, 2, 3]) * Polynomial([4, 5])) # (x^2 + 2*x + 3) * (4*x + 5) = 4*x^3 + 13*x^2 + 22*x + 15
Aliases: *
sqr
x.sqr
Returns the square of x. Equivalent to x * x.
say(Polynomial([1, 1]).sqr) # (x+1)^2 = x^2 + 2*x + 1
pow
a ** n
Returns a raised to the power n using binary (square-and-multiply) exponentiation.
say(Polynomial([1, 1]) ** 3) # (x+1)^3 = x^3 + 3*x^2 + 3*x + 1
If
nis a non-negative integer, returns the polynomial product.If
nis a negative integer, returns the multiplicative inverse ("inv") ofaraised to|n|— typically a rational function.If
nis not an integer, falls back toa.to_n.pow(n), converting the polynomial to a scalar first (only valid for constant polynomials).
Aliases: **
div
a / b
Divides a by b.
say(Polynomial([1, 0, -1]) / Polynomial([1, -1])) #=> x + 1
If
bis a polynomial and division is exact (zero remainder), returns the quotient polynomial.If the division is inexact, returns a
Sidef::Types::Number::Fractionrepresenting the rational function(q*b + r) / bwhereq,rare the quotient and remainder.If
bis zero, returns a polynomial with an infinite coefficient.If
bis a scalar, divides each coefficient byb.
Aliases: ÷
idiv
a // b
Returns only the quotient polynomial from Euclidean division, discarding the remainder. Equivalent to the first element of "divmod".
Note: The rounding-mode variants (idiv_ceil, idiv_floor, idiv_round, idiv_trunc) are all currently aliased to the same behaviour as plain idiv.
Aliases: //, idiv_ceil, idiv_floor, idiv_round, idiv_trunc
divmod
x.divmod(y)
Performs Euclidean polynomial long division and returns a two-element list (quotient, remainder) satisfying:
x == (quotient * y) + remainder
deg(remainder) < deg(y)
Returns (NaN, zero) if the leading coefficient of y is zero or NaN.
var (q, r) = Polynomial([1, 0, 0]) .divmod( Polynomial([1, 1]) ) #=> q = x-1, r = 1
mod
a % b
Returns the remainder polynomial from Euclidean division of a by b, i.e. the polynomial r of degree less than deg(b) satisfying a = q*b + r. When b is a scalar, each coefficient is reduced modulo b by wrapping it in a Sidef::Types::Number::Mod object.
say(Polynomial([1, 0, 0, 0]) % Polynomial([1, 0, 1])) # x^3 mod (x^2+1) = -x
Aliases: %
neg
x.neg
Returns the additive inverse of x: all coefficients are negated. Adding x and x.neg gives the zero polynomial.
say(Polynomial([1, 2, 3]).neg) # -x^2 - 2*x - 3
abs
x.abs
Returns x * x.sgn, i.e. the polynomial multiplied by the sign of its leading coefficient. This ensures the leading coefficient is positive. For the zero polynomial, returns zero.
say(Polynomial([-1, 2, -3]).abs) #=> x^2 - 2*x + 3
sgn
x.sgn
Returns the sign of the leading coefficient of x: -1, 0, or 1 as a Sidef::Types::Number::Number. Returns 0 for the zero polynomial.
inc
++a
Adds 1 to the constant term of a. Returns a new polynomial with the x^0 coefficient incremented by one.
var p = Polynomial([1, 2, 3])
say(++p) # x^2 + 2*x + 4
Aliases: ++
dec
--a
Subtracts 1 from the constant term of a. Returns a new polynomial with the x^0 coefficient decremented by one.
var p = Polynomial([1, 2, 3])
say(--p) # x^2 + 2*x + 2
Aliases: --
inv
x.inv
Returns a Sidef::Types::Number::Fraction representing 1/x. This creates the rational function 1 / x(t). Meaningful as an exact inverse only when x is a constant polynomial; for non-constant polynomials in a quotient ring, see Sidef::Types::Number::PolynomialMod.
invmod
x.invmod(m)
Computes x.mod(m).inv: reduces x modulo the polynomial m and then returns its multiplicative inverse. Equivalent to creating PolynomialMod(x, m).inv.
powmod
x.powmod(n, m)
Computes x^n mod m using binary (square-and-multiply) exponentiation, reducing modulo polynomial m after each multiplication step. More efficient than computing x**n and then taking % m separately for large n.
say(Polynomial([1, 1]).powmod(100, Polynomial([1, 0, 1])))
# (x+1)^100 mod (x^2+1)
GCD, LCM, AND FACTORIZATION
gcd
x.gcd(y)
Returns the greatest common divisor of polynomials x and y using the polynomial Euclidean algorithm. Handles zero polynomials explicitly: gcd(x, 0) = x and gcd(0, y) = y. The result is normalized to monic (leading coefficient equal to 1) before being returned.
var p = Polynomial([1, 0, -1]) # x^2 - 1
var q = Polynomial([1, -1]) # x - 1
say(p.gcd(q)) # x - 1 (monic)
gcdext
x.gcdext(y)
Extended Euclidean algorithm for polynomials. Returns a list of five values:
(g, u, v, a1, b1)
where g = gcd(x, y) and u, v are Bézout coefficient polynomials satisfying:
(u * x) + (v * y) == g
The additional values a1 and b1 are the final-step remainder polynomials scaled by a sign factor (-1)^i; they are the cofactors of the last non-trivial step and satisfy x/g = ±a1, y/g = ±b1 in the monic-normalised sense.
Note: The return list has five elements. If you only need the GCD and Bézout pair, capture just the first three:
var (g, u, v) = x.gcdext(y)
say(((u * x) + (v * y)) == g) # true
lcm
x.lcm(y)
Returns the least common multiple of polynomials x and y, computed as:
lcm(x, y) = abs(x * y) / gcd(x, y)
The abs ensures the leading coefficient of the result is positive.
normalize_to_monic
x.normalize_to_monic
Returns a monic version of x by dividing all coefficients by the leading coefficient. If the leading coefficient is already 1, returns x unchanged. If the leading coefficient is zero or the polynomial is empty, returns x unchanged.
say(Polynomial([3, 6, 9]).normalize_to_monic) # x^2 + 2*x + 3
is_monic
x.is_monic
Returns true if the leading coefficient of x is 1. Complements "normalize_to_monic".
content
x.content
Returns the content of the polynomial: the GCD of all its coefficients. Useful for extracting the largest scalar factor.
say(Polynomial([6, 9, 12]).content) # 3 (gcd(6,9,12))
Aliases: cont
primitive_part
x.primitive_part
Returns the primitive part of x: the polynomial divided by its content. The result has integer coefficients whose GCD is 1.
say(Polynomial([6, 9, 12]).primitive_part)
# (6*x^2 + 9*x + 12) / 3 = 2*x^2 + 3*x + 4
Aliases: prim_part, primpart
is_squarefree
x.is_squarefree
Returns true if x has no repeated irreducible factors, i.e. if gcd(x, x.derivative) equals 1 (the constant polynomial 1, monic of degree 0). Equivalently, x is square-free if and only if it shares no root with its own derivative.
say(Polynomial([1, 0, -1]).is_squarefree) # true (x^2-1 = (x-1)(x+1))
say(Polynomial([1, -2, 1]).is_squarefree) # false (x^2-2x+1 = (x-1)^2)
squarefree_part
x.squarefree_part
Returns the square-free part of x: the result of dividing x by gcd(x, x.derivative). The square-free part has the same roots as x but each root occurs with multiplicity at most 1.
say(Polynomial([1, -2, 1]).squarefree_part)
# (x-1)^2 → squarefree part is (x-1)
say(Polynomial([1, 0, 0, 0]).squarefree_part)
# x^3 → squarefree part is x
CALCULUS
derivative
x.derivative
Returns the formal derivative of x using the power rule: each term c_k * x^k maps to k * c_k * x^{k-1}. The constant term (k=0) is dropped. Works with any coefficient type, including complex or rational coefficients.
var p = Polynomial([1, 0, -3, 2]) # x^3 - 3*x + 2
say(p.derivative) # 3*x^2 - 3
eval
x.eval(value)
Evaluates the polynomial at value by computing the sum:
sum of: coeff_k * value^k for each nonzero term k
Each coefficient is itself evaluated at value via its own .eval method, allowing polynomials with polynomial coefficients (multivariate use). Returns 0 for the zero polynomial. As a special case, evaluating at the monomial x itself (i.e. Polynomial(1 = 1)>) returns the polynomial unchanged.
var p = Polynomial([1, 2, 3]) # x^2 + 2*x + 3
say(p.eval(5)) # 25 + 10 + 3 = 38
compose
p.compose(q)
Returns the polynomial p(q(x)) — substitutes the polynomial q for the variable in p, using polynomial arithmetic throughout (unlike "eval", which substitutes a scalar value).
var p = Polynomial([1, 0, 1]) # x^2 + 1
var q = Polynomial([1, 1]) # x + 1
say p.compose(q) # (x+1)^2 + 1 = x^2 + 2x + 2
ROOT FINDING
newton_method
f.newton_method
f.newton_method(x0)
f.newton_method(x0, df)
Applies Newton's method to find a root of f, starting from initial guess x0. Both x0 and df (the derivative polynomial) are optional:
x0defaults toNumber::i(the complex uniti = sqrt(-1)).dfdefaults tof.derivative.
The iteration x_{n+1} = x_n - f(x_n) / f'(x_n) runs for up to PREC steps (the current working precision). Returns the last refined approximation, which equals an actual root when convergence is detected (f(x) rounds to zero within precision).
var f = Polynomial([1, 0, -2]) # x^2 - 2
var df = f.derivative
say(f.newton_method(1.5, df)) # ≈ 1.41421356... (√2)
roots
f.roots
Attempts to find all roots of f numerically. Returns an Sidef::Types::Array::Array of root values (which may be complex numbers).
The algorithm:
- 1. Uses
deg(f)evenly-spaced roots of unity (slightly perturbed) as initial guesses. - 2. Refines all guesses simultaneously via the Aberth-Ehrlich method.
- 3. Polishes each candidate with Newton's method and deduplicates within working precision.
- 4. If fewer than
deg(f)distinct roots were found, retries with a series of transformed starting points (e.g. multiplied byi,exp, etc.) as a fallback.
For a constant polynomial (degree 0), no roots exist by construction and an empty array is returned. For polynomials with repeated roots, some roots may be missed.
say(Polynomial([1, 0, -1]).roots) # [-1, 1] (roots of x^2 - 1)
say(Polynomial([1, 0, 0, -1]).roots) # roots of x^3 - 1
roots_mod
poly.roots_mod(m)
Returns all roots of the polynomial modulo m.
Given a polynomial f(x) and a positive modulus m, this method finds every residue class x satisfying:
f(x) ≡ 0 (mod m)
The result is returned as an array of distinct roots, sorted in ascending order. If the polynomial has no roots modulo m, an empty array is returned.
var p = Polynomial([1, 0, -1]) # x^2 - 1
say p.roots_mod(7) # [1, 6]
var q = Polynomial([1, 0, 0, -1]) # x^3 - 1
say q.roots_mod(13) # [1, 3, 9]
var r = Polynomial([1, 3, 4, 2, 0, 5]) # x^5 + 3*x^4 + 4*x^3 + 2*x^2 + 5
say r.roots_mod(17) # [11, 14]
COMBINATORICS
binomial
n.binomial(k)
Computes the generalised binomial coefficient C(n, k) where n is a Polynomial and k is a non-negative integer, using the falling-factorial definition:
C(n, k) = (n * (n-1) * (n-2) * ... * (n-k+1)) / k!
The numerator product is computed via binary splitting for efficiency. Returns the constant polynomial 1 when k = 0.
var x = Polynomial(1) # x (monomial x^1)
say(x.binomial(2)) # x*(x-1)/2
INSPECTION
degree
x.degree
Returns the degree of the polynomial: the highest exponent with a non-zero coefficient, as a Sidef::Types::Number::Number. Returns 0 for the zero polynomial (the empty polynomial has no keys, so the fallback value is 0).
say(Polynomial([1, 2, 3]).degree) # 2
say(Polynomial([]).degree) # 0 (zero polynomial)
Aliases: deg
coeff
x.coeff(k)
Returns the coefficient of the term with exponent k. Returns 0 if no such term exists.
var p = Polynomial([3, 2, 1]) # 3*x^2 + 2*x + 1
say(p.coeff(0)) # 1 (constant term)
say(p.coeff(1)) # 2 (coefficient of x)
say(p.coeff(2)) # 3 (coefficient of x^2)
say(p.coeff(5)) # 0 (absent term)
Aliases: coefficient
coeffs
x.coeffs
Returns an Array of [exponent, coefficient] pairs for all nonzero terms, sorted in ascending order by exponent (lowest degree first).
var p = Polynomial([1, 2, 3]) # x^2 + 2*x + 3
say(p.coeffs)
# [[0, 3], [1, 2], [2, 1]]
# (constant term first, highest-degree term last)
Aliases: coefficients
exponents
x.exponents
Returns an Array of all exponents that have nonzero coefficients, sorted in ascending order.
say(Polynomial(5 => 3, 2 => 1).exponents) # [2, 5]
leading_coefficient
x.leading_coefficient
Returns the coefficient of the highest-degree term. Returns 0 for the zero polynomial.
say(Polynomial([3, 2, 1]).leading_coefficient) # 3
Aliases: leading_coeff
leading_term
x.leading_term
Returns the leading term of x as a Polynomial consisting of only the highest-degree term (with its coefficient intact).
say(Polynomial([3, 2, 1]).leading_term) # 3*x^2
leading_monomial
x.leading_monomial
Returns the leading monomial of x: the highest-degree term with its coefficient replaced by 1.
say(Polynomial([3, 2, 1]).leading_monomial) # x^2
height
x.height
Returns the maximum absolute value among all coefficients of x. Also called the infinity norm or Chebyshev norm of the coefficient vector.
say(Polynomial([3, -5, 2]).height) # 5
real
x.real
Returns the constant term (coefficient of x^0) of the polynomial, as a Sidef::Types::Number::Number. Returns 0 if no constant term is present. This reflects the embedding of scalars into the polynomial ring.
say(Polynomial([1, 2, 3]).real) # 3 (a Number, not a Polynomial)
Aliases: re
ROUNDING AND CONVERSION
float
x.float
Returns a new Polynomial with each coefficient converted to a floating-point approximation.
rat
x.rat
Returns a new Polynomial with each coefficient converted to an exact rational number (Math::GMPq).
rat_approx
x.rat_approx
Returns a new Polynomial with each floating-point coefficient replaced by a nearby rational approximation.
floor
x.floor
Returns a new Polynomial with floor() applied to each coefficient, rounding each one down to the nearest integer.
say(Polynomial([1.8, 2.3]).floor) # x + 2
ceil
x.ceil
Returns a new Polynomial with ceil() applied to each coefficient, rounding each one up to the nearest integer.
say(Polynomial([1.5, 2.3]).ceil) # 2*x + 3
round
x.round(r)
Returns a new Polynomial with each coefficient rounded to r decimal places (or to the nearest integer when r is zero).
say(Polynomial([1.456, 2.789]).round(1)) # 1.5*x + 2.8
lift
x.lift
Returns a new Polynomial with each coefficient replaced by its .lift value. For plain Number coefficients this is a no-op (returns an equivalent copy). For polynomials with Mod-valued coefficients (e.g. after calling .mod(n) on a polynomial over a modular ring), lift unwraps each coefficient from its modular context.
to_n
x.to_n
Converts the polynomial to a scalar Sidef::Types::Number::Number:
Zero polynomial (no terms): returns
0.Constant polynomial (only a
x^0term, all others zero or absent): returns the constant coefficient.Non-constant polynomial: returns
NaN.
to_poly
x.to_poly
Returns the polynomial itself. Provides a uniform interface for type conversion (e.g. PolynomialMod overrides this to return the underlying residue polynomial).
PREDICATES
is_real
x.is_real
Returns true if and only if x is effectively a real scalar constant: either the zero polynomial, or a polynomial with a single term at degree 0 whose coefficient satisfies .is_real. Returns false for any polynomial with a non-zero higher-degree term.
say(Polynomial([5]).is_real) # true (constant real)
say(Polynomial([1, 0]).is_real) # false (non-constant)
is_zero
x.is_zero
Returns true if x is the zero polynomial (no nonzero terms).
say(Polynomial([]).is_zero) # true (empty polynomial)
say(Polynomial([0, 1]).is_zero) # false (x is not zero)
is_one
x.is_one
Returns true if x equals the constant polynomial 1 (the multiplicative identity).
say(Polynomial([1]).is_one) # true
say(Polynomial([1, 0]).is_one) # false (this is x, not 1)
is_mone
x.is_mone
Returns true if x equals the constant polynomial -1.
is_nan
x.is_nan
Returns true if any coefficient of the polynomial is NaN. A NaN coefficient can appear as a result of invalid operations such as division by zero or failed modular inversion.
is_inf
x.is_inf
Returns true if any coefficient of the polynomial is positive infinity.
is_ninf
x.is_ninf
Returns true if any coefficient of the polynomial is negative infinity.
norm
x.norm
Returns the norm of the constant term: x.real.norm. This is the norm of the x^0 coefficient as a number, not the Euclidean norm of the coefficient vector.
COMPARISON
eq
a == b
Returns true if a equals b.
Polynomial vs Polynomial: true if every coefficient of
aequals the corresponding coefficient ofb(missing coefficients are treated as zero). Comparison is symmetric.Polynomial vs scalar: true if
ais a constant polynomial whosex^0coefficient equals the scalar, and all other coefficients are zero.
Aliases: ==
ne
a != b
Returns true if a and b are not equal. Implemented as the logical negation of "eq".
Aliases: !=
cmp
a <=> b
Three-way comparison. Returns -1, 0, or 1.
Polynomial vs Polynomial:
Polynomial vs scalar: only defined for constant polynomials (all non-constant coefficients zero). Returns
undeffor non-constant polynomials when compared against a scalar.
Aliases: <=>
lt
a < b
Returns true if a is strictly less than b under the ordering defined by "cmp".
Aliases: <
gt
a > b
Returns true if a is strictly greater than b.
Aliases: >
le
a <= b
Returns true if a is less than or equal to b.
Aliases: <=, ≤
ge
a >= b
Returns true if a is greater than or equal to b.
Aliases: >=, ≥
STRING REPRESENTATION AND BOOLEAN CONTEXT
to_s
x.to_s
Returns a Sidef::Types::String::String representation of the polynomial in standard mathematical notation, with terms ordered from highest to lowest degree:
say(Polynomial([1, 2, 3]).to_s) # "x^2 + 2*x + 3"
say(Polynomial([1, 0, -1]).to_s) # "x^2 - 1"
say(Polynomial([]).to_s) # "0"
Coefficient 1 is suppressed (x not 1*x); negative signs replace leading +. Parentheses are added around complex coefficients. This is also what a Polynomial produces when stringified implicitly (e.g. via interpolation).
Aliases: stringify
pretty
x.pretty
Like "to_s" but calls the .pretty method on each coefficient rather than .to_s. This may produce Unicode formatting (e.g. Unicode fractions or superscripts) depending on the coefficient type.
dump
x.dump
Returns a Sidef::Types::String::String showing the polynomial's internal sparse representation, suitable for debugging and round-tripping:
say(Polynomial([1, 2, 3]).dump)
# Polynomial(0 => 3, 1 => 2, 2 => 1)
Terms are listed in ascending exponent order with each coefficient shown via its own .dump.
__boolify__
self.__boolify__
Backs the polynomial's boolean-context overload (e.g. if polynomial_value). This checks only the constant term (the x^0 coefficient) — a polynomial with no constant term is falsy in a boolean context even if it has other nonzero terms, and one is not required to be the zero polynomial to be falsy this way.
if (Polynomial([1, 0])) { ... } # falsy: no constant term
if (Polynomial([1, 3])) { ... } # truthy: constant term is 3
EXAMPLES
Basic arithmetic
var p = Polynomial([1, -2, 1]) # x^2 - 2*x + 1 = (x-1)^2
var q = Polynomial([1, -1]) # x - 1
var sum = (p + q)
say(sum) # x^2 - x
var prod = (p * q)
say(prod) # x^3 - 3*x^2 + 3*x - 1
var (quot, rem) = p.divmod(q)
say(quot) # x - 1
say(rem) # 0
say(p.eval(3)) # 9 - 6 + 1 = 4
say(p.eval(1)) # 0 (1 is a double root)
Differentiation
var p = Polynomial([1, 0, -3, 2]) # x^3 - 3*x + 2
var dp = p.derivative
say(dp) # 3*x^2 - 3
say(dp.derivative) # 6*x
Root finding
say(Polynomial([1, 0, -1]).roots) # roots of x^2-1: [-1, 1]
say(Polynomial([1, 0, 1]).roots) # roots of x^2+1: [-i, i]
GCD, extended GCD, and Bézout identity
var p = Polynomial([1, 0, -1]) # x^2 - 1
var q = Polynomial([1, -1]) # x - 1
say(p.gcd(q)) # x - 1
var (g, u, v) = p.gcdext(q)
say(g) # x - 1
say(((u * p) + (v * q)) == g) # true
Content and primitive part
var r = Polynomial([6, 9, 12]) # 6*x^2 + 9*x + 12
say(r.content) # 3
say(r.primitive_part) # 2*x^2 + 3*x + 4
Square-free decomposition
var p = Polynomial([1, -2, 1]) # (x-1)^2
say(p.is_squarefree) # false
say(p.squarefree_part) # x - 1
Modular polynomial exponentiation
var base = Polynomial([1, 1]) # x + 1
var mod = Polynomial([1, 0, 1]) # x^2 + 1
say(base.powmod(10, mod))
# (x+1)^10 mod (x^2+1)
Sparse construction and inspection
var p = Polynomial(7 => 1, 3 => 5, 0 => 2) # x^7 + 5*x^3 + 2
say(p.degree) # 7
say(p.exponents) # [0, 3, 7]
say(p.coeff(3)) # 5
say(p.height) # 5
String constructor
var p = Polynomial("3*x^2 - 2*x + 1")
say(p.eval(0)) # 1
say(p.eval(1)) # 2
Newton's method
var f = Polynomial([1, 0, -2]) # x^2 - 2
var df = f.derivative # 2*x
say(f.newton_method(1.5, df)) # ≈ 1.41421356... (√2)
NOTES
Zero polynomial: The zero polynomial is represented as an empty hash (no keys). Its degree is 0, not -1 or -∞. Use
.is_zeroto test for it explicitly.Coefficient ring: Coefficients are arbitrary
Sidef::Types::Number::Numberobjects — integers, rationals, floats, or even complex numbers. There is no restriction to any particular coefficient ring.Division: The
/operator returns aSidef::Types::Number::Fractionwhen division is inexact. Use//(idiv) to always get just the quotient polynomial, ordivmodto get both quotient and remainder.Comparison vs scalar: The
<=>operator returnsundef(not a defined value) when comparing a non-constant polynomial against a scalar. Guard with a defined-check when this is possible.
REFERENCES
SEE ALSO
Sidef::Types::Number::Number, Sidef::Types::Number::PolynomialMod, Sidef::Types::Number::Fraction, Sidef::Types::Number::Mod