Symbolic expressions and closed forms
#include <flint/qqbar.h>void qqbar_get_quadratic(fmpz_t res_a, fmpz_t res_b, fmpz_t res_c, fmpz_t res_q, const qqbar_t x, int factoring)sourceFor x of degree 1 or 2, computes integers a, b, c, q with x = (a + b \sqrt{c})/q, q > 0, \gcd(a, b, q) = 1 and c not a perfect square; for rational x, b = c = 0.
For a Gaussian rational, c = -1. Otherwise c is derived from the discriminant according to factoring: 0 removes only factors of two, 1 factors completely so that c is squarefree (expensive for large discriminants), and 2 removes small square factors found by smooth factorisation, which gives nice output in most cases without the risk of a hard factorisation.
Sets res to the algebraic number given by the expression expr and returns 1, or returns 0 if expr is not understood.
The expression is evaluated statically with qqbar arithmetic; no symbolic simplification is done. Supported are integers, Decimal literals, arithmetic with algebraic operands, Sqrt, Pow with a rational exponent, the constants NumberI and GoldenRatio, RootOfUnity, Floor, Ceil, Abs, Sign, Csgn, Conjugate, Re, Im, Max, Min, trigonometric functions of rational multiples of Pi, Exp of rational multiples of Pi * NumberI, and the constructors AlgebraicNumberSerialized (whose data is trusted), PolynomialRootIndexed and PolynomialRootNearest. This covers the output of all qqbar_get_fexpr functions. Expressions such as Sub(Pi, Pi), Div(1, Infinity) or Sum(n, For(n, 1, 10)) are not supported, although their values are algebraic.
Sets res to AlgebraicNumberSerialized(List(coeffs), enclosure), which reflects the internal representation exactly. It can be read back with qqbar_set_fexpr cheaply and is the recommended format for serialisation, although it is not meant for human readers.
Sets res to PolynomialRootNearest(List(coeffs), point), where the decimal point is closer to x than to any other root, or to PolynomialRootIndexed(List(coeffs), index), where index (starting from 1) is the position of x among the roots in the order of qqbar_cmp_root_order. Both describe x unambiguously and readably, and can be read back with qqbar_set_fexpr, at the cost of root isolation.
Tries to write x as a closed-form expression with arithmetic operations, radicals and possibly exponentials or trigonometric functions, without PolynomialRootNearest or PolynomialRootIndexed. Returns 1 on success and 0 on failure. flags selects the methods (with flags = 0 only rational numbers are handled).
QQBAR_FORMULA_GAUSSIANSsourceQQBAR_FORMULA_QUADRATICSsourceQQBAR_FORMULA_CYCLOTOMICSsourceQQBAR_FORMULA_CUBICSsourceQQBAR_FORMULA_QUARTICSsourceQQBAR_FORMULA_QUINTICSsourceQQBAR_FORMULA_DEPRESSIONsourceQQBAR_FORMULA_DEFLATIONsourceQQBAR_FORMULA_SEPARATIONsourceQQBAR_FORMULA_ALLsourceMethods for qqbar_get_fexpr_formula: recognise Gaussian rationals a + bi; write quadratic numbers as a + b \sqrt{d}; recognise elements of cyclotomic fields, by trying plausible fields, finding candidate representations with LLL and verifying them exactly (heuristic, not guaranteed to find all); solve cubics, quartics and quintics (not yet implemented); depression (not yet implemented); deflation, which handles numbers a^{1/n} where a has a closed form; separation into real and imaginary parts a + bi or modulus and sign m s, tried as a fallback when the other methods fail. QQBAR_FORMULA_ALL enables all methods, which can be expensive.
QQBAR_FORMULA_EXP_FORMsourceQQBAR_FORMULA_TRIG_FORMsourceQQBAR_FORMULA_RADICAL_FORMsourceQQBAR_FORMULA_AUTO_FORMsourceThe form used for elements of cyclotomic fields. The automatic form (0, the default) gives radicals for numbers of low degree, trigonometric functions for real numbers and complex exponentials for nonreal numbers; the other flags (not fully implemented) request exponentials, trigonometric functions or radicals.
A qqbar_t can be converted to a symbolic expression (see fexpr.h) in three ways, and converted back with qqbar_set_fexpr.
qqbar_get_fexpr_reprwrites the internal representation exactly, asAlgebraicNumberSerialized(List(c_0, ..., c_d), enclosure). Reading it back costs no root isolation, so this is the format for storage and for transferring numbers between programs or contexts (ca_transferuses it).qqbar_get_fexpr_root_nearestandqqbar_get_fexpr_root_indexeddescribe the number as a root of its minimal polynomial, selected by a short decimal approximation or by its index in the canonical order. These are readable and unambiguous; reading them back requires isolating the roots.qqbar_get_fexpr_formulatries to find a closed form with radicals, trigonometric functions or exponentials. It succeeds for all numbers of degree at most 2, for elements of cyclotomic fields that it recognises, and for some numbers built from these by roots and by combining real and imaginary parts; otherwise it fails and returns 0.
Finding closed forms#
Every algebraic number of degree at most 4 can be written with radicals, and every element of an abelian extension of \mathbb{Q} is, by the Kronecker–Weber theorem, an element of a cyclotomic field \mathbb{Q}(\zeta_n), which gives closed forms with e^{2 \pi i/n} or with \cos and \sin of rational multiples of \pi. Most algebraic numbers of degree 5 and higher have no expression by radicals at all. qqbar_get_fexpr_formula uses the following methods, selected by the QQBAR_FORMULA_... flags.
- Gaussian rationals a + bi and quadratic numbers (a + b\sqrt{c})/q are written directly, using
qqbar_get_quadraticwith smooth factorisation to make c small. - Roots of unity are recognised from their cyclotomic minimal polynomials. For other numbers whose degree divides \varphi(n) for a plausible n, an expression as a polynomial in \zeta_n (or in 2 \cos(2\pi/n) for real numbers) is sought with LLL and verified exactly; the result is written in exponential or trigonometric form.
- Deflation: if the minimal polynomial is a polynomial in x^k, a closed form for x^k is sought recursively and the k-th root taken, with the correct branch.
- Separation: as a last resort, a formula is sought for the real and imaginary parts, or for the modulus and the sign, separately.
The cubic, quartic and quintic formulas and depression are not yet implemented, so a cubic irrationality that is not cyclotomic and not a pure root (such as a root of x^3 - x - 1) gets no formula.
Example#
The program prints closed forms for \cos(\pi/5), \cos(2\pi/7) (found in a cyclotomic field and written with trigonometric functions) and \sqrt[3]{2} + i (by separation into real and imaginary parts). A root of x^5 - x - 1 has no closed form and is written as the root of its minimal polynomial nearest to a decimal approximation. Finally the exact representation is written and read back.
#include <flint/fmpz_poly.h>
#include <flint/fexpr.h>
#include <flint/qqbar.h>
static void show(const qqbar_t x)
{
fexpr_t e;
fexpr_init(e);
if (!qqbar_get_fexpr_formula(e, x, QQBAR_FORMULA_ALL))
qqbar_get_fexpr_root_nearest(e, x);
fexpr_print(e);
flint_printf("\n");
fexpr_clear(e);
}
int main(void)
{
qqbar_t x, y;
qqbar_ptr r;
fmpz_poly_t f;
fexpr_t e;
char * s;
qqbar_init(x);
qqbar_init(y);
fexpr_init(e);
fmpz_poly_init(f);
r = _qqbar_vec_init(5);
qqbar_cos_pi(x, 1, 5); /* cos(pi/5) = (1 + sqrt(5))/4 */
show(x);
qqbar_cos_pi(x, 2, 7); /* cos(2 pi/7), degree 3 */
show(x);
qqbar_set_ui(x, 2); /* 2^(1/3) + i, degree 6 */
qqbar_root_ui(x, x, 3);
qqbar_i(y);
qqbar_add(x, x, y);
show(x);
fmpz_poly_set_str(f, "6 -1 -1 0 0 0 1"); /* x^5 - x - 1 */
qqbar_roots_fmpz_poly(r, f, 0);
show(r + 0);
qqbar_get_fexpr_repr(e, r + 0); /* exact serialization */
s = fexpr_get_str(e);
flint_printf("%.48s...\n", s);
flint_free(s);
qqbar_set_fexpr(y, e);
flint_printf("read back: %d\n", qqbar_equal(r + 0, y));
_qqbar_vec_clear(r, 5);
fmpz_poly_clear(f);
qqbar_clear(x);
qqbar_clear(y);
fexpr_clear(e);
return 0;
}Div(Add(1, Sqrt(5)), 4)
Div(Add(Mul(2, Cos(Div(Pi, 7))), Mul(2, Sin(Div(Pi, 14))), -1), 2)
Add(Pow(2, Div(1, 3)), Mul(1, NumberI))
PolynomialRootNearest(List(-1, -1, 0, 0, 0, 1), Decimal("1.16730"))
AlgebraicNumberSerialized(List(-1, -1, 0, 0, 0, ...
read back: 1The formula for \cos(2\pi/7) is correct but not the simplest one: the LLL search finds a short relation in the real cyclotomic field, which is then written term by term. Formulas are meant for presentation; they are not canonical, and two equal numbers can get different formulas. Use qqbar_get_fexpr_repr when the expression will be read by a program.
Guides#
- Using ca (
ca) - Building and printing expressions (
fexpr) - Using qqbar
The FLINT team, “Symbolic expressions and closed forms (qqbar.h),” FLINT: Fast Library for Number Theory, documentation, version 3.7.0-dev, 2026. https://flintlib.org/doc/qqbar/formulas.html (generated 2026-10-20).
@misc{flint-doc-qqbar-formulas,
author = {{The FLINT team}},
title = {{Symbolic expressions and closed forms (qqbar.h)}},
howpublished = {FLINT: Fast Library for Number Theory, documentation, version 3.7.0-dev},
year = {2026},
url = {https://flintlib.org/doc/qqbar/formulas.html},
note = {Generated 2026-10-20}
}