nfloat.h
#include <flint/nfloat.h>This module provides binary floating-point numbers with a precision of n full words, 1 \le n \le 66 on 64-bit machines (64 to 4224 bits), stored in a flat array of n + 2 words with no heap allocation, and complex numbers built from them. Because an element has a fixed size determined by the context, vectors and matrices of nfloat numbers are packed contiguously, temporaries can live on the stack, and every operation can switch to a kernel specialised for its number of words. The module is designed for the generic rings interface: a context created with nfloat_ctx_init is a gr_ctx_t, the functions return status codes, and gr_poly, gr_mat and the other generic modules work over it. For approximate polynomial root-finding and linear algebra this is about twice as fast as the same algorithms over arf_t or MPFR [Joh2025gr].
The focus is on speed, not on bitwise-specified results. Without directed rounding, the basic operations are correctly rounded toward zero or at most a few ulps off, and the elementary functions are accurate to about one ulp; with the directed rounding flags, most basic operations are correctly rounded and the other supported operations return valid bounds (see Rounding in nfloat). Results that are not correctly rounded may differ between 64-bit and 32-bit machines. For variable precision, precision above 4224 bits, or rigorous error bounds, use arf_t and arb_t; for 53 to 212 bits with SIMD-friendly double arithmetic, use dfloat; see Floating-point arithmetic in FLINT for a comparison.
The guide Getting started with nfloat shows how to use the module. The fixed-size kernels, the dot product and the matrix multiplication algorithms are described in Fixed-precision floating point with nfloat.
Guides#
Representation#
An element with n-word precision consists of n + 2 words: the exponent (an slong), the sign (a whole word, 0 or 1, to avoid bit manipulation), and the mantissa d_0, \ldots, d_{n-1}, least significant word first. A normal (nonzero finite) value is
where the mantissa is a fraction in [1/2, 1), so that the top bit of d_{n-1} is set and |x| \in [2^{e-1}, 2^e). The exponent is limited to about a quarter of the word range (NFLOAT_MIN_EXP to NFLOAT_MAX_EXP) so that sums of exponents cannot overflow. Zero, infinities and NaN are encoded by special exponent values, with arbitrary data in the mantissa.
The allowed numbers of words n: 1 \le n \le 66 on 64-bit machines and 1 \le n \le 132 on 32-bit machines, so at most 4224 bits. The upper limit keeps elements and temporary buffers small enough for the stack and makes copying and swapping cheap compared with a pointer-and-size representation.
NFLOAT_EXP(x)NFLOAT_D(x)NFLOAT_DATA(x)The number of header words, 2, and access to the exponent, the sign word, the mantissa (a pointer to d_0) and the whole element as an array of words.
The number of words of a temporary that can hold an element of any precision, NFLOAT_HEADER_LIMBS + NFLOAT_MAX_LIMBS.
The exponent range of normal values, \pmWORD_MAX / 4. Results outside this range underflow or overflow.
The exponent values encoding zero, +\infty, -\infty and NaN (all below NFLOAT_MIN_EXP), and tests for them. NFLOAT_IS_SPECIAL is true for zero, infinities and NaN.
Whether the most significant bit of the word n is set.
Types#
Pointers to an element or a vector of elements of any precision, as void * and const void *. Pointer arithmetic needs the element size from the context, for example through GR_ENTRY.
Structs of the right size for elements of some common precisions, for declaring elements on the stack; nfloatX_t is a length-one array of nfloatX_struct, so it is passed by reference. The precision of the context must match the type.
The context data: the number of words nlimbs, the flags, an unused rounding field rnd, and the function precision func_prec.
NFLOAT_CTX(ctx)NFLOAT_CTX_NLIMBS(ctx)NFLOAT_CTX_PREC(ctx)NFLOAT_CTX_FLAGS(ctx)NFLOAT_CTX_RND(ctx)NFLOAT_CTX_FUNC_PREC(ctx)Access to the context data: the number of words n, the precision n \cdot FLINT_BITS, the flags, the function precision, the element size n + 2 in words, and whether infinities or NaN, or directed rounding, are enabled.
Contexts#
int nfloat_ctx_init(gr_ctx_t ctx, slong prec, int flags)Initialises ctx to the ring of floating-point numbers with precision prec bits rounded up to a whole number of words (for example, prec = 53 gives 64-bit precision), with the given flags (a bitwise or of the flags below, or 0). Returns GR_UNABLE without initialising ctx if prec is not positive or exceeds the maximum NFLOAT_MAX_LIMBS * FLINT_BITS, and GR_SUCCESS otherwise. The context needs no memory and is cleared with gr_ctx_clear.
By default, a result that underflows the exponent range is set to zero and the operation returns GR_UNABLE. With this flag, it returns GR_SUCCESS with the zero result.
Allows infinities. By default, a result that overflows is set to zero (a garbage value) and the operation returns GR_UNABLE, and nfloat_pos_inf returns GR_DOMAIN; with this flag, overflow gives a signed infinity and GR_SUCCESS.
Allows NaN. By default, an operation without a meaningful result (such as 0/0 or \log(-1)) returns GR_UNABLE or GR_DOMAIN; with this flag, it outputs NaN and returns GR_SUCCESS.
Enable directed rounding toward -\infty or +\infty (experimental). At most one of them may be set. Without either, results are rounded in an unspecified direction, usually toward zero. Directed rounding may not work correctly together with NFLOAT_ALLOW_UNDERFLOW. Which operations respect it is listed in Rounding in nfloat.
Infinities and NaN are disabled by default because this lets many functions skip checks for them.
int nfloat_ctx_set_func_prec(gr_ctx_t ctx, slong prec)Set and get the function precision of ctx: the precision in bits to which the elementary functions (exponentials, logarithms, trigonometric and hyperbolic functions, their inverses and powers) are computed. It defaults to the full precision of the context; a value larger than that is clamped to it, and a value less than 1 makes nfloat_ctx_set_func_prec return GR_UNABLE. A smaller function precision makes these functions cheaper (for example, at 64 bits with a function precision of 50 bits, most functions evaluate their kernels with one word instead of two); the arithmetic is unaffected.
int nfloat_ctx_write(gr_stream_t out, gr_ctx_t ctx)Writes a description of ctx to out, such as Floating-point numbers with prec = 128 (nfloat).
int nfloat_ctx_set_real_prec(gr_ctx_t ctx, slong prec)int nfloat_ctx_get_real_prec(slong * res, gr_ctx_t ctx)The precision of a context cannot be changed: nfloat_ctx_set_real_prec does nothing and returns GR_UNABLE. nfloat_ctx_get_real_prec sets res to the precision in bits and returns GR_SUCCESS.
Memory management and constants#
The functions in this and the following sections implement the methods of the gr interface and can be used interchangeably with their gr counterparts (gr_add and so on), which dispatch to them.
void nfloat_init(nfloat_ptr res, gr_ctx_t ctx)void nfloat_clear(nfloat_ptr res, gr_ctx_t ctx)Initialise res to zero, and clear it. Since elements own no memory, clearing does nothing.
void nfloat_swap(nfloat_ptr x, nfloat_ptr y, gr_ctx_t ctx)int nfloat_set(nfloat_ptr res, nfloat_srcptr x, gr_ctx_t ctx)Swap two elements word by word, and copy x to res.
int nfloat_zero(nfloat_ptr res, gr_ctx_t ctx)int nfloat_one(nfloat_ptr res, gr_ctx_t ctx)int nfloat_neg_one(nfloat_ptr res, gr_ctx_t ctx)Set res to 0, 1 or -1.
int nfloat_pos_inf(nfloat_ptr res, gr_ctx_t ctx)int nfloat_neg_inf(nfloat_ptr res, gr_ctx_t ctx)int nfloat_nan(nfloat_ptr res, gr_ctx_t ctx)int nfloat_pi(nfloat_ptr res, gr_ctx_t ctx)Sets res to \pi rounded to the precision of the context.
Conversions#
int nfloat_set_ui(nfloat_ptr res, ulong x, gr_ctx_t ctx)int nfloat_set_si(nfloat_ptr res, slong x, gr_ctx_t ctx)int nfloat_set_fmpz(nfloat_ptr res, const fmpz_t x, gr_ctx_t ctx)int nfloat_set_fmpq(nfloat_ptr res, const fmpq_t v, gr_ctx_t ctx)int nfloat_set_d(nfloat_ptr res, double x, gr_ctx_t ctx)Set res to an integer, a rational number or a double, rounded to the precision of the context (toward zero, or in the direction of the context's directed rounding).
int nfloat_set_arf(nfloat_ptr res, const arf_t x, gr_ctx_t ctx)int nfloat_get_arf(arf_t res, nfloat_srcptr x, gr_ctx_t ctx)int nfloat_get_fmpz(fmpz_t res, nfloat_srcptr x, gr_ctx_t ctx)Sets res to x if x is an integer and returns GR_SUCCESS; returns GR_DOMAIN if x is not an integer and GR_UNABLE if it is infinite or NaN.
int nfloat_get_d_2exp_si(double * mant, slong * expo, nfloat_srcptr x, gr_ctx_t ctx)Sets mant and expo such that x \approx \mathit{mant} \cdot 2^{\mathit{expo}} with |\mathit{mant}| \in [1/2, 1) (or both zero for x = 0), from the leading word of the mantissa, so with a relative error of about 2^{-53}. This avoids the overflow of a direct conversion to double. Returns GR_UNABLE for infinities and NaN.
int nfloat_set_mpn_2exp(nfloat_ptr res, nn_srcptr x, slong xn, slong exp, int xsgnbit, gr_ctx_t ctx)int _nfloat_set_mpn_2exp(nfloat_ptr res, nn_srcptr x, slong xn, slong exp, int xsgnbit, gr_ctx_t ctx)Set res to (-1)^{\mathit{xsgnbit}} \cdot f \cdot 2^{\mathit{exp}}, where f = \{x, \mathit{xn}\} / 2^{\mathit{xn} \cdot \mathtt{FLINT\_BITS}} is the fraction in [0, 1) given by the xn words of x, rounded to the precision of the context. The version with an underscore requires that the top word x[xn - 1] is nonzero; the other removes leading zero words and handles f = 0.
int nfloat_1_set_2_2exp(nfloat_ptr res, ulong x1, ulong x0, slong exp, int xsgnbit, gr_ctx_t ctx)int nfloat_1_set_3_2exp(nfloat_ptr res, ulong x2, ulong x1, ulong x0, slong exp, int xsgnbit, gr_ctx_t ctx)int nfloat_2_set_3_2exp(nfloat_ptr res, ulong x2, ulong x1, ulong x0, slong exp, int xsgnbit, gr_ctx_t ctx)int nfloat_2_set_4_2exp(nfloat_ptr res, ulong x3, ulong x2, ulong x1, ulong x0, slong exp, int xsgnbit, gr_ctx_t ctx)Inline versions of nfloat_set_mpn_2exp for a two-, three- or four-word fraction (most significant word first in the argument list) and a context of exactly one word (nfloat_1_) or two words (nfloat_2_). The fraction is normalised and truncated (not rounded) to the precision; zero, underflow and overflow are handled as by the other functions.
int nfloat_set_str(nfloat_ptr res, const char * x, gr_ctx_t ctx)Parses a decimal number with arb_set_str and rounds it to nearest (this ignores directed rounding); other expressions are parsed with the generic string parser of the gr interface.
int nfloat_set_other(nfloat_ptr res, gr_srcptr x, gr_ctx_t x_ctx, gr_ctx_t ctx)int nfloat_write(gr_stream_t out, nfloat_srcptr x, gr_ctx_t ctx)int nfloat_randtest(nfloat_ptr res, flint_rand_t state, gr_ctx_t ctx)Write x in decimal as the arf_t ring of the same precision does, and set res to a random element (from arf_randtest) for testing.
Comparison#
truth_t nfloat_equal(nfloat_srcptr x, nfloat_srcptr y, gr_ctx_t ctx)truth_t nfloat_is_zero(nfloat_srcptr x, gr_ctx_t ctx)truth_t nfloat_is_one(nfloat_srcptr x, gr_ctx_t ctx)Return whether x is 0, 1 or -1; T_UNKNOWN for NaN.
int nfloat_cmp(int * res, nfloat_srcptr x, nfloat_srcptr y, gr_ctx_t ctx)int nfloat_cmpabs(int * res, nfloat_srcptr x, nfloat_srcptr y, gr_ctx_t ctx)Set res to -1, 0 or 1 according to the comparison of x and y, or of |x| and |y|, and return GR_SUCCESS; return GR_UNABLE if an operand is NaN.
int nfloat_sgn(nfloat_ptr res, nfloat_srcptr x, gr_ctx_t ctx)int nfloat_im(nfloat_ptr res, nfloat_srcptr x, gr_ctx_t ctx)Set res to the sign of x (-1, 0 or 1, and NaN for NaN), and to the imaginary part of x, which is zero.
Arithmetic#
int nfloat_neg(nfloat_ptr res, nfloat_srcptr x, gr_ctx_t ctx)int nfloat_abs(nfloat_ptr res, nfloat_srcptr x, gr_ctx_t ctx)Set res to -x or |x|, exactly.
int nfloat_add(nfloat_ptr res, nfloat_srcptr x, nfloat_srcptr y, gr_ctx_t ctx)int nfloat_sub(nfloat_ptr res, nfloat_srcptr x, nfloat_srcptr y, gr_ctx_t ctx)int nfloat_mul(nfloat_ptr res, nfloat_srcptr x, nfloat_srcptr y, gr_ctx_t ctx)int nfloat_sqr(nfloat_ptr res, nfloat_srcptr x, gr_ctx_t ctx)Sum, difference, product and square. Without directed rounding the error is less than 2 ulp for the sum and difference (the smaller operand is truncated when it is aligned) and at most 1 ulp for the products (truncation, except that the approximate high product used from three words on can rarely give one ulp less in magnitude); with directed rounding the results are correctly rounded.
Moreint nfloat_addmul(nfloat_ptr res, nfloat_srcptr x, nfloat_srcptr y, gr_ctx_t ctx)int nfloat_submul(nfloat_ptr res, nfloat_srcptr x, nfloat_srcptr y, gr_ctx_t ctx)Set res to \mathit{res} + xy or \mathit{res} - xy, with two roundings, so the result can be far from the exact value (measured in ulp of the result) when the terms cancel.
int nfloat_mul_2exp_si(nfloat_ptr res, nfloat_srcptr x, slong y, gr_ctx_t ctx)Sets res to x \cdot 2^y, exactly unless the result overflows or underflows.
int nfloat_inv(nfloat_ptr res, nfloat_srcptr x, gr_ctx_t ctx)int nfloat_div(nfloat_ptr res, nfloat_srcptr x, nfloat_srcptr y, gr_ctx_t ctx)int nfloat_div_ui(nfloat_ptr res, nfloat_srcptr x, ulong y, gr_ctx_t ctx)int nfloat_div_si(nfloat_ptr res, nfloat_srcptr x, slong y, gr_ctx_t ctx)Inverse and quotients. Without directed rounding, the result is the quotient truncated toward zero or, for divisors of three or more nonzero words, possibly one ulp larger in magnitude (an error of less than 1 ulp); div_ui and div_si are always truncated. With directed rounding, the result is the correctly rounded floor or ceiling of the exact quotient. Division by zero gives NaN, so it returns GR_UNABLE unless NaN is allowed.
int nfloat_sqrt(nfloat_ptr res, nfloat_srcptr x, gr_ctx_t ctx)int nfloat_rsqrt(nfloat_ptr res, nfloat_srcptr x, gr_ctx_t ctx)Square root and reciprocal square root. The square root is correctly rounded in every mode (truncated toward zero by default); the reciprocal square root has an error of less than 1 + 2^{-37} ulp by default and is correctly rounded with directed rounding. Negative arguments give NaN.
Moreint nfloat_hypot(nfloat_ptr res, nfloat_srcptr x, nfloat_srcptr y, gr_ctx_t ctx)Sets res to \sqrt{x^2 + y^2}, correctly rounded in every mode (truncated by default), without intermediate overflow or underflow. This also implements nfloat_complex_abs.
int nfloat_floor(nfloat_ptr res, nfloat_srcptr x, gr_ctx_t ctx)int nfloat_ceil(nfloat_ptr res, nfloat_srcptr x, gr_ctx_t ctx)int nfloat_trunc(nfloat_ptr res, nfloat_srcptr x, gr_ctx_t ctx)int nfloat_nint(nfloat_ptr res, nfloat_srcptr x, gr_ctx_t ctx)Round x to an integer toward -\infty, toward +\infty, toward zero, or to the nearest integer (ties to even). The results are exact.
Elementary functions#
The elementary functions are computed natively, on the mantissas, with the fixed-point kernels of the mp_real module (table-based argument reduction and rectangular splitting of the Taylor series [Joh2014c]; see Elementary functions in mp_real); nfloat precisions never need bit-burst evaluation. The results are not correctly rounded: without directed rounding the error is at most about one ulp at the function precision of the context (see nfloat_ctx_set_func_prec), and with directed rounding the result is a valid lower or upper bound within a few ulps. Exact special cases give exact results (for example \exp(0), \log 1, \sin(\pi x) for multiples of 1/2, \log_2 of powers of two). Results that overflow or underflow follow the flags of the context, and arguments outside the real domain (such as \log of a negative number or \operatorname{asin} of |x| > 1) give NaN, so they return GR_UNABLE or GR_DOMAIN unless NaN is allowed.
On 64-bit machines, nfloat_exp, nfloat_expm1, nfloat_log, nfloat_log1p, nfloat_pow, nfloat_sin_cos, nfloat_sin, nfloat_cos, nfloat_tan, nfloat_cot, their versions at \pi x, nfloat_sinh_cosh, nfloat_sinh, nfloat_cosh, nfloat_tanh, nfloat_coth, nfloat_atan and nfloat_atan2 have in-register fast paths at one and two words for common arguments (for example every argument below the overflow threshold for the exponential, and 2^{-33} \le |x| < 2^{63} for the sine and cosine at one word): the argument reduction on the mantissa, the table-driven kernels of mp_real at two or three words (shared with its 128- and 192-bit functions), and the final normalisation, without temporary arrays. The hyperbolic functions use a paired kernel for e^t and e^{-t} (and one division for tanh and coth), the tangent and cotangent divide the sine and the cosine in registers, nfloat_pow multiplies a logarithm with one more word (or two, for large |y|) by y exactly before the exponential, and the arctangent of |x| > 1 and nfloat_atan2 evaluate the arctangent of a ratio of mantissas with a single division. Arguments where the reduced argument would lose relative accuracy (close to 1 for the logarithm, close to a multiple of \pi/2 for the sine, cosine and tangent, very small arguments of expm1, log1p and sinh) and rarer ranges take the general path.
From three to nine words the general path runs on the dense-table kernels of mp_real at four to ten words, and from ten to thirty-one words on the dense-table kernels with tables computed at run time (shared by all threads and built on first use).
Otherwise the functions wrap the ball functions of mp_real (for example mp_real_sin_cos_bits), evaluated on the exact argument at increasing precision until the ball determines the result. This handles trigonometric functions of huge arguments (exponent above 65536, up to 2^{22}, beyond which GR_UNABLE is returned), the less common functions for arguments whose intermediate results overflow or underflow, and the maximum precision NFLOAT_MAX_LIMBS, which leaves no room for a guard word.
int nfloat_exp(nfloat_ptr res, nfloat_srcptr x, gr_ctx_t ctx)int nfloat_expm1(nfloat_ptr res, nfloat_srcptr x, gr_ctx_t ctx)int nfloat_exp2(nfloat_ptr res, nfloat_srcptr x, gr_ctx_t ctx)int nfloat_log(nfloat_ptr res, nfloat_srcptr x, gr_ctx_t ctx)int nfloat_log1p(nfloat_ptr res, nfloat_srcptr x, gr_ctx_t ctx)int nfloat_log2(nfloat_ptr res, nfloat_srcptr x, gr_ctx_t ctx)Exponentials e^x, e^x - 1, 2^x and logarithms \log x, \log(1 + x), \log_2 x. The exponentials reduce |x| modulo \log 2 in fixed point (with one integral word); expm1 and log1p have relative accuracy near zero, and exp2 and log2 are exact for integers and powers of two respectively.
int nfloat_sin(nfloat_ptr res, nfloat_srcptr x, gr_ctx_t ctx)int nfloat_cos(nfloat_ptr res, nfloat_srcptr x, gr_ctx_t ctx)int nfloat_sin_cos(nfloat_ptr res1, nfloat_ptr res2, nfloat_srcptr x, gr_ctx_t ctx)int nfloat_tan(nfloat_ptr res, nfloat_srcptr x, gr_ctx_t ctx)int nfloat_sin_pi(nfloat_ptr res, nfloat_srcptr x, gr_ctx_t ctx)int nfloat_cos_pi(nfloat_ptr res, nfloat_srcptr x, gr_ctx_t ctx)int nfloat_sin_cos_pi(nfloat_ptr res1, nfloat_ptr res2, nfloat_srcptr x, gr_ctx_t ctx)int nfloat_tan_pi(nfloat_ptr res, nfloat_srcptr x, gr_ctx_t ctx)Sine, cosine and tangent of x and of \pi x; the sin_cos versions compute both. The argument is reduced modulo \pi/2 in fixed point, repeated with more bits when the reduced argument is close to a zero of the result, so that the results have relative accuracy; the functions of \pi x reduce x modulo 2 exactly.
int nfloat_atan(nfloat_ptr res, nfloat_srcptr x, gr_ctx_t ctx)int nfloat_atan2(nfloat_ptr res, nfloat_srcptr y, nfloat_srcptr x, gr_ctx_t ctx)The arctangent, and the two-argument arctangent \operatorname{atan2}(y, x) \in (-\pi, \pi]. For |x| > 1, atan uses \pi/2 - \operatorname{atan}(1/|x|); atan2 takes the arctangent of the ratio of the smaller and the larger magnitude and adds the octant. \operatorname{atan2}(0, 0) = 0.
int nfloat_sinh(nfloat_ptr res, nfloat_srcptr x, gr_ctx_t ctx)int nfloat_cosh(nfloat_ptr res, nfloat_srcptr x, gr_ctx_t ctx)int nfloat_sinh_cosh(nfloat_ptr res1, nfloat_ptr res2, nfloat_srcptr x, gr_ctx_t ctx)int nfloat_tanh(nfloat_ptr res, nfloat_srcptr x, gr_ctx_t ctx)Hyperbolic functions, from E = e^{|x|} and 1/E, with the difference E - 1/E computed in fixed point for |x| < 1.
int nfloat_pow(nfloat_ptr res, nfloat_srcptr x, nfloat_srcptr y, gr_ctx_t ctx)Sets res to x^y = \exp(y \log|x|), with the sign (-1)^y for x < 0 and integer y (NaN for x < 0 and noninteger y). Simple cases (y = \pm 1, 2, \pm 1/2, |x| = 1, integer powers of powers of two) are handled directly.
int nfloat_exp10(nfloat_ptr res, nfloat_srcptr x, gr_ctx_t ctx)int nfloat_log10(nfloat_ptr res, nfloat_srcptr x, gr_ctx_t ctx)int nfloat_cot(nfloat_ptr res, nfloat_srcptr x, gr_ctx_t ctx)int nfloat_sec(nfloat_ptr res, nfloat_srcptr x, gr_ctx_t ctx)int nfloat_csc(nfloat_ptr res, nfloat_srcptr x, gr_ctx_t ctx)int nfloat_sinc(nfloat_ptr res, nfloat_srcptr x, gr_ctx_t ctx)int nfloat_cot_pi(nfloat_ptr res, nfloat_srcptr x, gr_ctx_t ctx)int nfloat_sec_pi(nfloat_ptr res, nfloat_srcptr x, gr_ctx_t ctx)int nfloat_csc_pi(nfloat_ptr res, nfloat_srcptr x, gr_ctx_t ctx)int nfloat_sinc_pi(nfloat_ptr res, nfloat_srcptr x, gr_ctx_t ctx)int nfloat_coth(nfloat_ptr res, nfloat_srcptr x, gr_ctx_t ctx)int nfloat_sech(nfloat_ptr res, nfloat_srcptr x, gr_ctx_t ctx)int nfloat_csch(nfloat_ptr res, nfloat_srcptr x, gr_ctx_t ctx)int nfloat_asin(nfloat_ptr res, nfloat_srcptr x, gr_ctx_t ctx)int nfloat_acos(nfloat_ptr res, nfloat_srcptr x, gr_ctx_t ctx)int nfloat_asin_pi(nfloat_ptr res, nfloat_srcptr x, gr_ctx_t ctx)int nfloat_acos_pi(nfloat_ptr res, nfloat_srcptr x, gr_ctx_t ctx)int nfloat_atan_pi(nfloat_ptr res, nfloat_srcptr x, gr_ctx_t ctx)int nfloat_acot(nfloat_ptr res, nfloat_srcptr x, gr_ctx_t ctx)int nfloat_asec(nfloat_ptr res, nfloat_srcptr x, gr_ctx_t ctx)int nfloat_acsc(nfloat_ptr res, nfloat_srcptr x, gr_ctx_t ctx)int nfloat_acot_pi(nfloat_ptr res, nfloat_srcptr x, gr_ctx_t ctx)int nfloat_asec_pi(nfloat_ptr res, nfloat_srcptr x, gr_ctx_t ctx)int nfloat_acsc_pi(nfloat_ptr res, nfloat_srcptr x, gr_ctx_t ctx)int nfloat_asinh(nfloat_ptr res, nfloat_srcptr x, gr_ctx_t ctx)int nfloat_acosh(nfloat_ptr res, nfloat_srcptr x, gr_ctx_t ctx)int nfloat_atanh(nfloat_ptr res, nfloat_srcptr x, gr_ctx_t ctx)int nfloat_acoth(nfloat_ptr res, nfloat_srcptr x, gr_ctx_t ctx)int nfloat_asech(nfloat_ptr res, nfloat_srcptr x, gr_ctx_t ctx)int nfloat_acsch(nfloat_ptr res, nfloat_srcptr x, gr_ctx_t ctx)The less common elementary functions. After the exact special values (zeros, poles, |x| = 1 for the inverse functions, multiples of 1/2 for the functions of \pi x), they are evaluated as short compositions of the functions above in an internal context with a guard word (none when the function precision is sufficiently below the precision), using formulas without cancellation, such as \operatorname{asin}(x) = \operatorname{atan2}(x, \sqrt{(1 - x)(1 + x)}) and \operatorname{asinh}(x) = \operatorname{log1p}(|x| + x^2/(1 + \sqrt{1 + x^2})), and a rigorous bound for the composed error, which is added to obtain valid bounds with directed rounding.
Moreint nfloat_gamma(nfloat_ptr res, nfloat_srcptr x, gr_ctx_t ctx)int nfloat_zeta(nfloat_ptr res, nfloat_srcptr x, gr_ctx_t ctx)Vector functions#
These override the generic gr vector operations with inlined or partially inlined code, which avoids the per-element dispatch.
void _nfloat_vec_init(nfloat_ptr res, slong len, gr_ctx_t ctx)void _nfloat_vec_clear(nfloat_ptr res, slong len, gr_ctx_t ctx)int _nfloat_vec_set(nfloat_ptr res, nfloat_srcptr x, slong len, gr_ctx_t ctx)int _nfloat_vec_zero(nfloat_ptr res, slong len, gr_ctx_t ctx)Initialise a vector of len elements to zero, clear it (no-op), copy and zero.
int _nfloat_vec_add(nfloat_ptr res, nfloat_srcptr x, nfloat_srcptr y, slong len, gr_ctx_t ctx)int _nfloat_vec_sub(nfloat_ptr res, nfloat_srcptr x, nfloat_srcptr y, slong len, gr_ctx_t ctx)int _nfloat_vec_mul(nfloat_ptr res, nfloat_srcptr x, nfloat_srcptr y, slong len, gr_ctx_t ctx)int _nfloat_vec_mul_scalar(nfloat_ptr res, nfloat_srcptr x, slong len, nfloat_srcptr y, gr_ctx_t ctx)int _nfloat_vec_addmul_scalar(nfloat_ptr res, nfloat_srcptr x, slong len, nfloat_srcptr y, gr_ctx_t ctx)int _nfloat_vec_submul_scalar(nfloat_ptr res, nfloat_srcptr x, slong len, nfloat_srcptr y, gr_ctx_t ctx)Elementwise sum, difference and product, product with the scalar y, and \mathit{res}_i \pm x_i y, with the same results as the scalar functions.
int _nfloat_vec_div(nfloat_ptr res, nfloat_srcptr x, nfloat_srcptr y, slong len, gr_ctx_t ctx)int _nfloat_vec_div_scalar(nfloat_ptr res, nfloat_srcptr x, slong len, nfloat_srcptr c, gr_ctx_t ctx)int _nfloat_vec_div_scalar_ui(nfloat_ptr res, nfloat_srcptr x, slong len, ulong c, gr_ctx_t ctx)int _nfloat_vec_div_scalar_si(nfloat_ptr res, nfloat_srcptr x, slong len, slong c, gr_ctx_t ctx)Elementwise quotients and quotients by a scalar, with the same results as the scalar division, except that _nfloat_vec_div_scalar for three or more words and a divisor of two or more nonzero words may differ by up to 1 ulp without directed rounding.
int _nfloat_vec_dot(nfloat_ptr res, nfloat_srcptr initial, int subtract, nfloat_srcptr x, nfloat_srcptr y, slong len, gr_ctx_t ctx)int _nfloat_vec_dot_rev(nfloat_ptr res, nfloat_srcptr initial, int subtract, nfloat_srcptr x, nfloat_srcptr y, slong len, gr_ctx_t ctx)Set res to s \pm \sum_{i} x_i y_i (or with y reversed), where s is initial (zero if NULL) and the sign is negative if subtract is nonzero. The sum is accumulated in fixed point with one guard word after a pass that finds the largest exponent, so the result has an error of a few ulps relative to the largest term rather than one rounding per term; with directed rounding it is a valid bound. See Dot products.
Matrix functions#
These implement the gr_mat methods of the nfloat contexts; the generic algorithms (solving, inversion, determinants, ...) use them through the method table.
int nfloat_mat_mul(gr_mat_t C, const gr_mat_t A, const gr_mat_t B, gr_ctx_t ctx)Sets C = AB, choosing between classical multiplication with the dot product, nfloat_mat_mul_fixed and nfloat_mat_mul_block according to the dimensions and the precision (tuned cutoffs). Contexts with infinities, NaN or directed rounding, and matrices with a dimension of at most 2, always use classical multiplication. The methods are described in Matrix multiplication.
int nfloat_mat_mul_fixed(gr_mat_t C, const gr_mat_t A, const gr_mat_t B, slong max_extra_prec, gr_ctx_t ctx)Sets C = AB by converting A and B to fixed-point matrices with common exponents and multiplying them with _nfixed_mat_mul. The fixed-point precision is the target precision plus the spread of the exponents in A and in B plus a few guard bits; returns GR_UNABLE if this exceeds the target by max_extra_prec bits or more, if a matrix has zero entries (but is not zero), or if infinities or NaN are enabled.
int nfloat_mat_mul_block(gr_mat_t C, const gr_mat_t A, const gr_mat_t B, slong min_block_size, gr_ctx_t ctx)Sets C = AB by splitting the inner dimension into blocks in which the entries of each row of A and each column of B have similar exponents, scaling the blocks to integer matrices and multiplying them exactly with fmpz_mat_mul (multimodular or FFT methods), as arb_mat_mul_block [Joh2019dot]. Blocks shorter than min_block_size are handled with dot products.
int nfloat_mat_nonsingular_solve_tril(gr_mat_t X, const gr_mat_t L, const gr_mat_t B, int unit, gr_ctx_t ctx)int nfloat_mat_nonsingular_solve_triu(gr_mat_t X, const gr_mat_t L, const gr_mat_t B, int unit, gr_ctx_t ctx)int nfloat_mat_lu(slong * rank, slong * P, gr_mat_t LU, const gr_mat_t A, int rank_check, gr_ctx_t ctx)int nfloat_mat_lq(gr_mat_t L, gr_mat_t Q, const gr_mat_t A, gr_ctx_t ctx)Triangular solving, LU factorisation and LQ factorisation, choosing between the classical (Gram–Schmidt for LQ) and the recursive versions of the generic algorithms (gr_mat_nonsingular_solve_tril_classical, gr_mat_lu_recursive, gr_mat_lq_recursive, ...) by precision-dependent cutoffs, so that large problems run on fast matrix multiplication.
Complex numbers#
Complex numbers are pairs of nfloat numbers, the real part followed by the imaginary part, so an element has 2(n + 2) words. The context is created with nfloat_complex_ctx_init and has the same data as the real context, so that the real functions can be applied to the parts. The arithmetic and elementary functions are approximate: each part typically has an error of a few ulps relative to the magnitude of the result, and directed rounding is not supported except by nfloat_complex_abs.
Pointers to complex elements (the same as nfloat_ptr and nfloat_srcptr).
int nfloat_complex_ctx_init(gr_ctx_t ctx, slong prec, int flags)Initialises ctx to the ring of complex numbers whose parts have precision prec bits rounded up to a whole number of words, with the flags of nfloat_ctx_init. Returns GR_UNABLE if the precision is out of range.
NFLOAT_COMPLEX_RE(ptr, ctx)NFLOAT_COMPLEX_IM(ptr, ctx)NFLOAT_COMPLEX_IS_SPECIAL(x, ctx)NFLOAT_COMPLEX_IS_ZERO(x, ctx)The size of a complex element in words, pointers to the real and imaginary parts, and tests whether a part is special or both parts are zero.
void nfloat_complex_init(nfloat_complex_ptr res, gr_ctx_t ctx)void nfloat_complex_clear(nfloat_complex_ptr res, gr_ctx_t ctx)void nfloat_complex_swap(nfloat_complex_ptr x, nfloat_complex_ptr y, gr_ctx_t ctx)int nfloat_complex_set(nfloat_complex_ptr res, nfloat_complex_ptr x, gr_ctx_t ctx)int nfloat_complex_zero(nfloat_complex_ptr res, gr_ctx_t ctx)int nfloat_complex_one(nfloat_complex_ptr res, gr_ctx_t ctx)int nfloat_complex_neg_one(nfloat_complex_ptr res, gr_ctx_t ctx)int nfloat_complex_i(nfloat_complex_ptr res, gr_ctx_t ctx)int nfloat_complex_pi(nfloat_complex_ptr res, gr_ctx_t ctx)Memory management and constants, as for the real numbers; i sets res to the imaginary unit.
int nfloat_complex_get_acf(acf_t res, nfloat_complex_srcptr x, gr_ctx_t ctx)int nfloat_complex_set_acf(nfloat_complex_ptr res, const acf_t x, gr_ctx_t ctx)int nfloat_complex_get_acb(acb_t res, nfloat_complex_srcptr x, gr_ctx_t ctx)int nfloat_complex_set_acb(nfloat_complex_ptr res, const acb_t x, gr_ctx_t ctx)int nfloat_complex_set_si(nfloat_complex_ptr res, slong x, gr_ctx_t ctx)int nfloat_complex_set_ui(nfloat_complex_ptr res, ulong x, gr_ctx_t ctx)int nfloat_complex_set_fmpz(nfloat_complex_ptr res, const fmpz_t x, gr_ctx_t ctx)int nfloat_complex_set_fmpq(nfloat_complex_ptr res, const fmpq_t x, gr_ctx_t ctx)int nfloat_complex_set_d(nfloat_complex_ptr res, double x, gr_ctx_t ctx)int nfloat_complex_set_other(nfloat_complex_ptr res, gr_srcptr x, gr_ctx_t x_ctx, gr_ctx_t ctx)int nfloat_complex_write(gr_stream_t out, nfloat_complex_srcptr x, gr_ctx_t ctx)int nfloat_complex_randtest(nfloat_complex_ptr res, flint_rand_t state, gr_ctx_t ctx)Conversions from real values (with zero imaginary part) and from other rings, output, and random elements.
int nfloat_complex_cmp(int * res, nfloat_complex_srcptr x, nfloat_complex_srcptr y, gr_ctx_t ctx)int nfloat_complex_cmpabs(int * res, nfloat_complex_srcptr x, nfloat_complex_srcptr y, gr_ctx_t ctx)Predicates and comparisons. cmp compares real numbers and returns GR_DOMAIN if an imaginary part is nonzero; cmpabs compares absolute values.
int nfloat_complex_conj(nfloat_complex_ptr res, nfloat_complex_srcptr x, gr_ctx_t ctx)int nfloat_complex_re(nfloat_complex_ptr res, nfloat_complex_srcptr x, gr_ctx_t ctx)int nfloat_complex_im(nfloat_complex_ptr res, nfloat_complex_srcptr x, gr_ctx_t ctx)int nfloat_complex_neg(nfloat_complex_ptr res, nfloat_complex_srcptr x, gr_ctx_t ctx)int nfloat_complex_add(nfloat_complex_ptr res, nfloat_complex_srcptr x, nfloat_complex_srcptr y, gr_ctx_t ctx)int nfloat_complex_sub(nfloat_complex_ptr res, nfloat_complex_srcptr x, nfloat_complex_srcptr y, gr_ctx_t ctx)int nfloat_complex_mul(nfloat_complex_ptr res, nfloat_complex_srcptr x, nfloat_complex_srcptr y, gr_ctx_t ctx)int nfloat_complex_sqr(nfloat_complex_ptr res, nfloat_complex_srcptr x, gr_ctx_t ctx)int nfloat_complex_mul_2exp_si(nfloat_complex_ptr res, nfloat_complex_srcptr x, slong y, gr_ctx_t ctx)int nfloat_complex_abs(nfloat_ptr res, nfloat_complex_srcptr x, gr_ctx_t ctx)Conjugate, real and imaginary parts (as complex numbers), negation, sum, difference, product, square, multiplication by 2^y and absolute value (a real number, correctly rounded as by nfloat_hypot).
int nfloat_complex_inv(nfloat_complex_ptr res, nfloat_complex_srcptr x, gr_ctx_t ctx)int nfloat_complex_div(nfloat_complex_ptr res, nfloat_complex_srcptr x, nfloat_complex_srcptr y, gr_ctx_t ctx)int nfloat_complex_sqrt(nfloat_complex_ptr res, nfloat_complex_srcptr x, gr_ctx_t ctx)int nfloat_complex_rsqrt(nfloat_complex_ptr res, nfloat_complex_srcptr x, gr_ctx_t ctx)Inverse, quotient, square root and reciprocal square root (principal branches), with errors of a few ulps relative to the magnitude of the result. Purely real or imaginary operands are handled with the real functions.
Moreint nfloat_complex_exp(nfloat_complex_ptr res, nfloat_complex_srcptr x, gr_ctx_t ctx)int nfloat_complex_expm1(nfloat_complex_ptr res, nfloat_complex_srcptr x, gr_ctx_t ctx)int nfloat_complex_exp_pi_i(nfloat_complex_ptr res, nfloat_complex_srcptr x, gr_ctx_t ctx)int nfloat_complex_exp2(nfloat_complex_ptr res, nfloat_complex_srcptr x, gr_ctx_t ctx)int nfloat_complex_exp10(nfloat_complex_ptr res, nfloat_complex_srcptr x, gr_ctx_t ctx)int nfloat_complex_log(nfloat_complex_ptr res, nfloat_complex_srcptr x, gr_ctx_t ctx)int nfloat_complex_log1p(nfloat_complex_ptr res, nfloat_complex_srcptr x, gr_ctx_t ctx)int nfloat_complex_log_pi_i(nfloat_complex_ptr res, nfloat_complex_srcptr x, gr_ctx_t ctx)int nfloat_complex_log2(nfloat_complex_ptr res, nfloat_complex_srcptr x, gr_ctx_t ctx)int nfloat_complex_log10(nfloat_complex_ptr res, nfloat_complex_srcptr x, gr_ctx_t ctx)int nfloat_complex_sin(nfloat_complex_ptr res, nfloat_complex_srcptr x, gr_ctx_t ctx)int nfloat_complex_cos(nfloat_complex_ptr res, nfloat_complex_srcptr x, gr_ctx_t ctx)int nfloat_complex_sin_cos(nfloat_complex_ptr res1, nfloat_complex_ptr res2, nfloat_complex_srcptr x, gr_ctx_t ctx)int nfloat_complex_tan(nfloat_complex_ptr res, nfloat_complex_srcptr x, gr_ctx_t ctx)int nfloat_complex_cot(nfloat_complex_ptr res, nfloat_complex_srcptr x, gr_ctx_t ctx)int nfloat_complex_sec(nfloat_complex_ptr res, nfloat_complex_srcptr x, gr_ctx_t ctx)int nfloat_complex_csc(nfloat_complex_ptr res, nfloat_complex_srcptr x, gr_ctx_t ctx)int nfloat_complex_sin_pi(nfloat_complex_ptr res, nfloat_complex_srcptr x, gr_ctx_t ctx)int nfloat_complex_cos_pi(nfloat_complex_ptr res, nfloat_complex_srcptr x, gr_ctx_t ctx)int nfloat_complex_sin_cos_pi(nfloat_complex_ptr res1, nfloat_complex_ptr res2, nfloat_complex_srcptr x, gr_ctx_t ctx)int nfloat_complex_tan_pi(nfloat_complex_ptr res, nfloat_complex_srcptr x, gr_ctx_t ctx)int nfloat_complex_cot_pi(nfloat_complex_ptr res, nfloat_complex_srcptr x, gr_ctx_t ctx)int nfloat_complex_sec_pi(nfloat_complex_ptr res, nfloat_complex_srcptr x, gr_ctx_t ctx)int nfloat_complex_csc_pi(nfloat_complex_ptr res, nfloat_complex_srcptr x, gr_ctx_t ctx)int nfloat_complex_sinc(nfloat_complex_ptr res, nfloat_complex_srcptr x, gr_ctx_t ctx)int nfloat_complex_sinc_pi(nfloat_complex_ptr res, nfloat_complex_srcptr x, gr_ctx_t ctx)int nfloat_complex_sinh(nfloat_complex_ptr res, nfloat_complex_srcptr x, gr_ctx_t ctx)int nfloat_complex_cosh(nfloat_complex_ptr res, nfloat_complex_srcptr x, gr_ctx_t ctx)int nfloat_complex_sinh_cosh(nfloat_complex_ptr res1, nfloat_complex_ptr res2, nfloat_complex_srcptr x, gr_ctx_t ctx)int nfloat_complex_tanh(nfloat_complex_ptr res, nfloat_complex_srcptr x, gr_ctx_t ctx)int nfloat_complex_coth(nfloat_complex_ptr res, nfloat_complex_srcptr x, gr_ctx_t ctx)int nfloat_complex_sech(nfloat_complex_ptr res, nfloat_complex_srcptr x, gr_ctx_t ctx)int nfloat_complex_csch(nfloat_complex_ptr res, nfloat_complex_srcptr x, gr_ctx_t ctx)int nfloat_complex_asin(nfloat_complex_ptr res, nfloat_complex_srcptr x, gr_ctx_t ctx)int nfloat_complex_acos(nfloat_complex_ptr res, nfloat_complex_srcptr x, gr_ctx_t ctx)int nfloat_complex_atan(nfloat_complex_ptr res, nfloat_complex_srcptr x, gr_ctx_t ctx)int nfloat_complex_acot(nfloat_complex_ptr res, nfloat_complex_srcptr x, gr_ctx_t ctx)int nfloat_complex_asec(nfloat_complex_ptr res, nfloat_complex_srcptr x, gr_ctx_t ctx)int nfloat_complex_acsc(nfloat_complex_ptr res, nfloat_complex_srcptr x, gr_ctx_t ctx)int nfloat_complex_asinh(nfloat_complex_ptr res, nfloat_complex_srcptr x, gr_ctx_t ctx)int nfloat_complex_acosh(nfloat_complex_ptr res, nfloat_complex_srcptr x, gr_ctx_t ctx)int nfloat_complex_atanh(nfloat_complex_ptr res, nfloat_complex_srcptr x, gr_ctx_t ctx)int nfloat_complex_acoth(nfloat_complex_ptr res, nfloat_complex_srcptr x, gr_ctx_t ctx)int nfloat_complex_asech(nfloat_complex_ptr res, nfloat_complex_srcptr x, gr_ctx_t ctx)int nfloat_complex_acsch(nfloat_complex_ptr res, nfloat_complex_srcptr x, gr_ctx_t ctx)int nfloat_complex_asin_pi(nfloat_complex_ptr res, nfloat_complex_srcptr x, gr_ctx_t ctx)int nfloat_complex_acos_pi(nfloat_complex_ptr res, nfloat_complex_srcptr x, gr_ctx_t ctx)int nfloat_complex_atan_pi(nfloat_complex_ptr res, nfloat_complex_srcptr x, gr_ctx_t ctx)int nfloat_complex_acot_pi(nfloat_complex_ptr res, nfloat_complex_srcptr x, gr_ctx_t ctx)int nfloat_complex_asec_pi(nfloat_complex_ptr res, nfloat_complex_srcptr x, gr_ctx_t ctx)int nfloat_complex_acsc_pi(nfloat_complex_ptr res, nfloat_complex_srcptr x, gr_ctx_t ctx)int nfloat_complex_pow(nfloat_complex_ptr res, nfloat_complex_srcptr x, nfloat_complex_srcptr y, gr_ctx_t ctx)void _nfloat_complex_vec_init(nfloat_complex_ptr res, slong len, gr_ctx_t ctx)void _nfloat_complex_vec_clear(nfloat_complex_ptr res, slong len, gr_ctx_t ctx)int _nfloat_complex_vec_zero(nfloat_complex_ptr res, slong len, gr_ctx_t ctx)int _nfloat_complex_vec_set(nfloat_complex_ptr res, nfloat_complex_srcptr x, slong len, gr_ctx_t ctx)int _nfloat_complex_vec_add(nfloat_complex_ptr res, nfloat_complex_srcptr x, nfloat_complex_srcptr y, slong len, gr_ctx_t ctx)int _nfloat_complex_vec_sub(nfloat_complex_ptr res, nfloat_complex_srcptr x, nfloat_complex_srcptr y, slong len, gr_ctx_t ctx)int _nfloat_complex_vec_dot(nfloat_complex_ptr res, nfloat_complex_srcptr initial, int subtract, nfloat_complex_srcptr x, nfloat_complex_srcptr y, slong len, gr_ctx_t ctx)int _nfloat_complex_vec_dot_rev(nfloat_complex_ptr res, nfloat_complex_srcptr initial, int subtract, nfloat_complex_srcptr x, nfloat_complex_srcptr y, slong len, gr_ctx_t ctx)Vector operations on complex numbers, as for the real vectors; the dot products accumulate the real and imaginary parts in fixed point.
int nfloat_complex_mat_mul(gr_mat_t C, const gr_mat_t A, const gr_mat_t B, gr_ctx_t ctx)int nfloat_complex_mat_mul_fixed(gr_mat_t C, const gr_mat_t A, const gr_mat_t B, slong max_extra_prec, gr_ctx_t ctx)int nfloat_complex_mat_mul_block(gr_mat_t C, const gr_mat_t A, const gr_mat_t B, slong min_block_size, gr_ctx_t ctx)int nfloat_complex_mat_mul_reorder(gr_mat_t C, const gr_mat_t A, const gr_mat_t B, gr_ctx_t ctx)Complex matrix multiplication, as for the real matrices. The fixed-point and block versions use three real products (the Karatsuba formula (AC - BD) + ((A + B)(C + D) - AC - BD)i); nfloat_complex_mat_mul_reorder separates the real and imaginary parts into real matrices and multiplies them with nfloat_mat_mul (with fewer products when A or B is real). nfloat_complex_mat_mul uses the reordering for real factors and for parts that are not well scaled.
int nfloat_complex_mat_nonsingular_solve_tril(gr_mat_t X, const gr_mat_t L, const gr_mat_t B, int unit, gr_ctx_t ctx)int nfloat_complex_mat_nonsingular_solve_triu(gr_mat_t X, const gr_mat_t L, const gr_mat_t B, int unit, gr_ctx_t ctx)int nfloat_complex_mat_lu(slong * rank, slong * P, gr_mat_t LU, const gr_mat_t A, int rank_check, gr_ctx_t ctx)Triangular solving and LU factorisation, choosing between the classical and recursive generic algorithms by precision-dependent cutoffs.
Fixed-point arithmetic#
The matrix multiplication of nfloat_mat_mul_fixed works on packed fixed-point numbers in (-1, 1) with n-word precision, stored as n + 1 words: a sign word followed by the n words of the absolute value, least significant first. In these functions, nlimbs is n while the storage is nlimbs + 1 words. There is no overflow handling: inputs must be scaled so that all intermediate results, including rounding errors, stay in (-1, 1), which _nfixed_mat_mul_bound checks.
void _nfixed_print(nn_srcptr x, slong nlimbs, slong exp)Prints the fixed-point number x times 2^{\mathit{exp}} in decimal.
Elementwise sum and difference of vectors of len fixed-point numbers (exact).
Dot products of fixed-point vectors with 2 to 8 words, accumulating truncated high products in separate positive and negative sums. The strides are the offsets in words between consecutive entries and may be negative.
void _nfixed_mat_mul_classical(nn_ptr C, nn_srcptr A, nn_srcptr B, slong m, slong n, slong p, slong nlimbs)void _nfixed_mat_mul_classical_precise(nn_ptr C, nn_srcptr A, nn_srcptr B, slong m, slong n, slong p, slong nlimbs)void _nfixed_mat_mul_waksman(nn_ptr C, nn_srcptr A, nn_srcptr B, slong m, slong n, slong p, slong nlimbs)void _nfixed_mat_mul_strassen(nn_ptr C, nn_srcptr A, nn_srcptr B, slong m, slong n, slong p, slong cutoff, slong nlimbs)Set the m \times p matrix C to the product of the m \times n matrix A and the n \times p matrix B (dense, row-major). The classical version uses the dot products; the _precise version computes with one extra word and is intended for testing. Waksman's algorithm [Waksman1970] halves the number of multiplications at the cost of more additions, which pays off from about 9 words. Strassen's algorithm [Str1969] recurses down to cutoff (a negative value selects the default). _nfixed_mat_mul chooses: Strassen for dimensions above about 26 to 57 (depending on the precision and parity), otherwise Waksman or classical.
void _nfixed_mat_mul_bound(double * bound, double * error, slong m, slong n, slong p, double A, double B, slong nlimbs)void _nfixed_mat_mul_bound_classical(double * bound, double * error, slong m, slong n, slong p, double A, double B, slong nlimbs)void _nfixed_mat_mul_bound_waksman(double * bound, double * error, slong m, slong n, slong p, double A, double B, slong nlimbs)void _nfixed_mat_mul_bound_strassen(double * bound, double * error, slong m, slong n, slong p, double A, double B, slong cutoff, slong nlimbs)void _nfixed_complex_mat_mul_bound(double * bound, double * error, slong m, slong n, slong p, double A, double B, double C, double D, slong nlimbs)For an m \times n \times p product at precision nlimbs with entries of A and B bounded by A and B, set bound to a bound for all intermediate values of the corresponding algorithm, which must be less than 1 for the computation to be valid, and error to a bound for the output error in ulps. _nfixed_mat_mul_bound follows the algorithm choice of _nfixed_mat_mul. The bounds are nondecreasing in A and B. For complex matrices, the entries are bounded by A + Bi and C + Di.
Internal functions#
int _nfloat_underflow(nfloat_ptr res, int sgnbit, gr_ctx_t ctx)int _nfloat_overflow(nfloat_ptr res, int sgnbit, gr_ctx_t ctx)Set res to the result of an underflow (zero, returning GR_SUCCESS only with NFLOAT_ALLOW_UNDERFLOW) or an overflow (a signed infinity with NFLOAT_ALLOW_INF, otherwise zero and GR_UNABLE).
NFLOAT_HANDLE_UNDERFLOW(res, ctx)NFLOAT_HANDLE_OVERFLOW(res, ctx)NFLOAT_HANDLE_UNDERFLOW_OVERFLOW(res, ctx)Return from the enclosing function with the result of _nfloat_underflow or _nfloat_overflow if the exponent of res is out of range.
int _nfloat_cmp(nfloat_srcptr x, nfloat_srcptr y, gr_ctx_t ctx)int _nfloat_cmpabs(nfloat_srcptr x, nfloat_srcptr y, gr_ctx_t ctx)Return -1, 0 or 1 according to the comparison of x and y, or of |x| and |y|; neither may be NaN.
int _nfloat_add_1(nfloat_ptr res, ulong x0, slong xexp, int xsgnbit, ulong y0, slong delta, gr_ctx_t ctx)int _nfloat_sub_1(nfloat_ptr res, ulong x0, slong xexp, int xsgnbit, ulong y0, slong delta, gr_ctx_t ctx)int _nfloat_add_2(nfloat_ptr res, nn_srcptr xd, slong xexp, int xsgnbit, nn_srcptr yd, slong delta, gr_ctx_t ctx)int _nfloat_sub_2(nfloat_ptr res, nn_srcptr xd, slong xexp, int xsgnbit, nn_srcptr yd, slong delta, gr_ctx_t ctx)int _nfloat_add_3(nfloat_ptr res, nn_srcptr x, slong xexp, int xsgnbit, nn_srcptr y, slong delta, gr_ctx_t ctx)int _nfloat_sub_3(nfloat_ptr res, nn_srcptr x, slong xexp, int xsgnbit, nn_srcptr y, slong delta, gr_ctx_t ctx)int _nfloat_add_4(nfloat_ptr res, nn_srcptr x, slong xexp, int xsgnbit, nn_srcptr y, slong delta, gr_ctx_t ctx)int _nfloat_sub_4(nfloat_ptr res, nn_srcptr x, slong xexp, int xsgnbit, nn_srcptr y, slong delta, gr_ctx_t ctx)int _nfloat_add_n(nfloat_ptr res, nn_srcptr xd, slong xexp, int xsgnbit, nn_srcptr yd, slong delta, slong nlimbs, gr_ctx_t ctx)int _nfloat_sub_n(nfloat_ptr res, nn_srcptr xd, slong xexp, int xsgnbit, nn_srcptr yd, slong delta, slong nlimbs, gr_ctx_t ctx)The fixed-size kernels of addition and subtraction of magnitudes: set res to (-1)^{\mathit{xsgnbit}} (|x| \pm |y|), where x has mantissa x and exponent xexp, and y has mantissa y and exponent xexp - delta with \mathit{delta} \ge 0 (so |x| \ge |y| in exponent, and for subtraction |x| \ge |y|). The mantissas have 1, 2, 3, 4 or nlimbs words.
int _nfloat_complex_sqr_naive(nfloat_ptr res1, nfloat_ptr res2, nfloat_srcptr a, nfloat_srcptr b, gr_ctx_t ctx)int _nfloat_complex_sqr_standard(nfloat_ptr res1, nfloat_ptr res2, nfloat_srcptr a, nfloat_srcptr b, gr_ctx_t ctx)int _nfloat_complex_sqr_karatsuba(nfloat_ptr res1, nfloat_ptr res2, nfloat_srcptr a, nfloat_srcptr b, gr_ctx_t ctx)int _nfloat_complex_sqr(nfloat_ptr res1, nfloat_ptr res2, nfloat_srcptr a, nfloat_srcptr b, gr_ctx_t ctx)int _nfloat_complex_mul_naive(nfloat_ptr res1, nfloat_ptr res2, nfloat_srcptr a, nfloat_srcptr b, nfloat_srcptr c, nfloat_srcptr d, gr_ctx_t ctx)int _nfloat_complex_mul_standard(nfloat_ptr res1, nfloat_ptr res2, nfloat_srcptr a, nfloat_srcptr b, nfloat_srcptr c, nfloat_srcptr d, gr_ctx_t ctx)int _nfloat_complex_mul_karatsuba(nfloat_ptr res1, nfloat_ptr res2, nfloat_srcptr a, nfloat_srcptr b, nfloat_srcptr c, nfloat_srcptr d, gr_ctx_t ctx)Set res1 and res2 to the real and imaginary parts of (a + bi)^2 or (a + bi)(c + di) with real nfloat parts: naive with real products and sums, standard with fused dot products of two terms, and karatsuba with three real products instead of four. _nfloat_complex_sqr uses the naive version when infinities or NaN are enabled, real squarings when a part is zero, and otherwise the standard version below 20 words and the Karatsuba version from 20 words.
References#
- [Joh2025gr] F. Johansson. Generic rings in FLINT. Preprint, 2025. https://fredrikj.net/math/flintgenerics.pdf
- [Joh2014c] F. Johansson, "Efficient implementation of elementary functions in the medium-precision range", 22nd IEEE Symposium on Computer Arithmetic (ARITH 22), 83-89 (2015), https://arxiv.org/abs/1410.7176
- [Joh2019dot] F. Johansson. Faster arbitrary-precision dot product and matrix multiplication. Proceedings of the 26th IEEE Symposium on Computer Arithmetic (ARITH-26), 2019, 15–22. https://arxiv.org/abs/1901.04289
- [Waksman1970] Waksman, Abraham, "On Winograd's algorithm for inner products", IEEE Transactions on Computers 19.04 (1970): 360-361.
- [Str1969] V. Strassen, "Gaussian elimination is not optimal", Numerische Mathematik 13 (1969), 354-356, https://doi.org/10.1007/BF02165411
The FLINT team, “nfloat.h (module overview),” FLINT: Fast Library for Number Theory, documentation, version 3.7.0-dev, 2026. https://flintlib.org/doc/nfloat/index.html (generated 2026-10-20).
@misc{flint-doc-nfloat-index,
author = {{The FLINT team}},
title = {{nfloat.h (module overview)}},
howpublished = {FLINT: Fast Library for Number Theory, documentation, version 3.7.0-dev},
year = {2026},
url = {https://flintlib.org/doc/nfloat/index.html},
note = {Generated 2026-10-20}
}