Elementary functions of balls
#include <flint/mp_real.h>Set res1 and res2 to balls containing \sin y and \cos y for every y in x. Either output may be NULL. The sine keeps its relative accuracy for small |x|; near the other zeros the loss of significance shows in the radius. Arguments with |x| \ge 2^{\max(65536, 4\,\mathit{prec})} give [0 \pm 1].
If x is inexact, prec is first lowered to a few bits beyond the accuracy its radius allows (relative for |x| < 1, absolute otherwise), and the radius is added to both outputs at the end (as |\sin'|, |\cos'| \le 1). A ball inside (-1, 1) whose radius exceeds a quarter of its midpoint gives [0 \pm 2^e] and 1 \pm 2^{2e-1} for |x| < 2^e; a wider ball elsewhere gives [0 \pm 1].
For a midpoint with z leading zero bits (|m| < 2^{-z}): if 2z \ge \mathit{prec} + 3 the results are m and 1, and if 4z \ge \mathit{prec} + 3 they are m - m^3/6 and 1 - m^2/2, with the Taylor remainders in the radius. Otherwise, for |m| < 1, the fixed-point kernel is called on |m| at \mathit{prec} + z bits plus guard bits (or a series for the reduced argument when z is large). For |m| \ge 1 the argument is reduced modulo \pi/2, with the quotient chosen so that the remainder is nonnegative, folded to [0, \pi/4], and the outputs are permuted and negated according to the quotient modulo 4. The reduction adds at most 3 ulps to the kernel's bound and is not repeated at a higher precision near zeros.
Set res to a ball containing \tan y for every y in x and return 1, or return 0 with res set to zero when the ball may contain a pole (or |x| \ge 2^{\max(65536, 4\,\mathit{prec})}). The result keeps its relative accuracy near the zeros and poles of the tangent.
After the reduction |m| = a\pi/2 + sv, v \in [0, \pi/4], the result is s \tan v for even a and -s/\tan v for odd a (one Newton reciprocal). Near a zero or a pole v is small, so the kernel runs with the leading zero bits of v as extra precision, and the reduction is repeated at that precision when the first pass had fewer limbs. An exact m is never a multiple of \pi/2, and by the irrationality measure of \pi a b-bit m lies at least about 2^{-7.2 b} away from one; the repetition is capped at 8b + 1024 extra bits (status 0 beyond). For an inexact x no repetition is made once v falls below the radius.
The radius r of x enters through a pole test: with T enclosing \tan m and U = r(1 + |T|) \ge r/|\cos m|, U < 1 implies that the ball contains no pole, and then |\tan y - \tan m| \le r(1 + T^2)/(1 - U)^2.
The same as mp_real_sin_cos_bits and mp_real_tan_bits for \sin(\pi y), \cos(\pi y) and \tan(\pi y). The argument reduction is exact, so the outputs keep their relative accuracy near every zero (and the tangent near every pole) at any magnitude of x, and the values at multiples of 1/2 (and of the tangent at odd multiples of 1/4) are exact.
The midpoint is dyadic, and its units bit and fraction bits give |m| = a/2 + st with a \in \{0, 1, 2, 3\}, s = \pm 1 and t \in [0, 1/4] exactly. Then v = \pi t enters the formulas of the reduction modulo \pi/2; t = 0 gives 0 or \pm 1 (and a pole of the tangent for odd a, status 0), and t = 1/4 the exact \tan(\pi/4) = 1. Otherwise t has z leading zero bits and the kernel runs at z extra bits. The radius r of x is a radius \pi r of the argument; \pi r \ge 1/4 gives [0 \pm 1] for the sine and cosine.
Set res1 and res2 to balls containing \sin(\pi p/q) and \cos(\pi p/q), respectively res to \tan(\pi p/q), for words p \ge 0 and q \ge 1, to a relative accuracy of about B^{-n}. Either output of the first function may be NULL; the two must be distinct. The tangent returns 0 with res set to zero at a pole, else 1. The rational values 0, \pm 1, \pm 1/2 are exact. Both throw for q = 0.
The fraction is reduced to lowest terms and folded by the symmetries to \pi t/q with 0 \le 2t \le q. The nonzero values of \sin(\pi t/q) and \cos(\pi t/q) are at least 1/q, so _mp_real_sin_cos_pi_ui_div_ui at n + \lceil(\operatorname{bits}(q) + 16)/\mathtt{FLINT\_BITS}\rceil limbs gives the relative accuracy. The tangent uses the closed forms \sqrt 3, 1/\sqrt 3, \sqrt 2 \mp 1, 2 \mp \sqrt 3 for q = 3, 6, 8, 12 and \sqrt{5 \mp 2\sqrt 5}, \sqrt{1 \mp 2/\sqrt 5} for q = 5, 10 (from 12 limbs), the Chebyshev sine and cosine and one division for the denominators where they win, and the tangent kernel otherwise.
Set res to a ball containing \exp(y), \log(y) resp. \operatorname{atan}(y) for every y in x. The results keep their relative accuracy near \exp(y) = 1, \log(y) = 0 and \operatorname{atan}(y) = 0. mp_real_exp_bits throws for |y| \ge 2^{\mathtt{FLINT\_BITS} - 5}, where the exponent of the result would leave the safe range. mp_real_log_bits returns 0 with res set to zero unless the ball is strictly positive, and 1 otherwise.
The radius \rho of x enters as the factor [1 \pm (e^\rho - 1)] (exp), as \rho/(m - \rho) (log, by the mean value theorem), and as \rho, or \rho/(|m| - \rho)^2 when the ball stays beyond 1 in absolute value (atan). An exp ball too wide for two correct bits gives [0 \pm e^{m + \rho}].
- exp: |m| = q \log 2 + t, t \in [0, \log 2), with q from two limbs of 1/\log 2 and one multiply-subtract by \log 2; for m < 0 the quotient is rounded up and the remainder complemented, so that \exp(m) = 2^{-q}\exp(t) directly. Small |m| use 1 + m, 1 + m + m^2/2, ... or a series for the reduced argument.
- log: with m = 2^E u, u \in [1/2, 1), \log m = (E - 1)\log 2 + \operatorname{log1p}(2u - 1) up to 600 limbs and E \log 2 - (-\log u) by
_mp_real_neglog_newtonabove; near 1, 2\operatorname{atanh}(s/(2 \pm s)) for s = |m - 1|, or the first terms of \log(1 + D). - atan: \operatorname{atan}(m) = \pi/4 + \operatorname{atan}(s/(2+s)) for 1 < m < 2, s = m - 1, and \pi/2 - \operatorname{atan}(1/m) for m \ge 2; \operatorname{atan}(1) = \pi/4.
At few limbs the per-size kernels are called directly on the argument's limbs in place.
Set res (rs to \sinh and rc to \cosh, either may be NULL) to a ball containing \log(1 + y), e^y - 1, \sinh y, \cosh y, \tanh y, \operatorname{asin} y, \operatorname{acos} y, \operatorname{asinh} y, \operatorname{acosh} y resp. \operatorname{atanh} y for every y in x. The results keep their relative accuracy at the zeros of the functions, and tiny and huge arguments are handled without squaring them. The functions returning int return 0 with res set to zero when the ball is not certified to lie in the domain, and 1 otherwise.
The domains are: 1 + y > 0 for log1p, |y| < 1 for atanh, and for asin, acos and acosh |y| \le 1 resp. y \ge 1 for an exact argument and strictly inside for an inexact one. mp_real_expm1_bits throws like mp_real_exp_bits for y \ge 2^{\mathtt{FLINT\_BITS} - 5}, and mp_real_sinh_cosh_bits for |y| \ge 2^{\mathtt{FLINT\_BITS} - 5}; expm1 of a large negative argument gives -1 with a tiny radius.
The functions are compositions of mp_real_exp_bits, mp_real_log_bits and mp_real_atan_bits by formulas without cancellation: \operatorname{log1p}(y) = \log(1 + y) with 1 + y formed exactly (or to \mathit{prec} + z bits for |y| < 2^{-z}); \operatorname{expm1} from \exp at \mathit{prec} + z bits; \sinh and \cosh from \operatorname{expm1}(\pm m); \tanh(m) = \operatorname{expm1}(2m)/(\operatorname{expm1}(2m) + 2); \operatorname{asin}(m) = \operatorname{atan}(m/\sqrt{(1 - m)(1 + m)}) and \operatorname{acos}(m) = 2\operatorname{atan}(\sqrt{(1 - m)/(1 + m)}) with 1 \pm m exact; \operatorname{asinh}(m) = \operatorname{log1p}(|m| + m^2/(1 + \sqrt{1 + m^2})); \operatorname{acosh}(m) = \operatorname{log1p}(d + \sqrt{d(m + 1)}) with d = m - 1 exact; and \operatorname{atanh}(m) = \operatorname{log1p}(2|m|/(1 - |m|))/2. Tiny and huge arguments use the leading terms with a bounded remainder (m, \log(2|m|), \pm 1), and \operatorname{asin}(\pm 1), \operatorname{acos}(\pm 1) and \operatorname{acosh}(1) are exact. The radius \rho enters through a bound for the variation over the ball, for example \rho \cosh(|m| + \rho) for \sinh and \rho/(1 - |m| - \rho) for atanh.
Set res to a ball containing \exp(y) for every y in x, to a relative accuracy of about B^{-n}, without the precomputed tables of mp_real_exp_bits. These are meant for a single exponential at huge precision, where building the tables does not pay. The ball handling and the range |y| < 2^{\mathtt{FLINT\_BITS} - 5} are those of mp_real_exp_bits.
mp_real_exp_notab_log2reduces by \log 2 (computing and caching \log 2) and calls_mp_real_exp_notab; it is the fastest when \log 2 is already cached.mp_real_exp_notab_squaringneeds no \log 2: \exp(|m|) = \exp(|m| 2^{-s})^{2^s} with |m| 2^{-s} < 1/2, the reduced value from_mp_real_exp_notaband s ball squarings (with s + 16 guard bits), and one reciprocal for m < 0. It is faster than the reduction when \log 2 must be computed.mp_real_exp_agmcomputes y_0 = \exp(m) to a fraction of the precision by the squarings and corrects it by one Newton–Taylor step on the AGM logarithm of y_0 (Elementary functions in mp_real), in O(M(n) \log n). It calls the squarings below about 30 limbs and overtakes them at about 15000 limbs.
These functions evaluate exp, log, the trigonometric and hyperbolic functions and their inverses on mp_real_t balls. They take a target precision in bits rather than limbs and choose their working precision themselves, so that the result has a relative accuracy of about 2^{-\mathit{prec}} whenever the argument allows it.
Common behaviour#
- Midpoint and radius. The midpoint m of the argument is evaluated exactly as given, with all its limbs, and the radius \rho is propagated at the end through a bound for the variation of the function over the ball (for exp, the factor 1 \pm (e^\rho - 1); for log, \rho/(m - \rho)). When the radius limits the accuracy,
precis first lowered to a few bits beyond what the radius allows, so that no time is spent on digits the radius would swamp. - Relative accuracy near zeros. The results keep their relative accuracy where the function value is small: \exp near 0 (through
mp_real_expm1_bits), \log near 1, \sin, \tan, \operatorname{atan}, \sinh, \tanh, \operatorname{asin}, \operatorname{asinh} and \operatorname{atanh} near 0, \operatorname{acos} and \operatorname{acosh} near 1. The argument reduction adds the leading zero bits of the reduced argument to the working precision. The functions of \pi x reduce exactly and keep relative accuracy near every zero; \sin x and \cos x near nonzero multiples of \pi show the cancellation of the reduction in their radius instead. - Domains. The functions with a restricted domain return an
int: 1 on success, or 0 with the output set to zero when the ball is not certified to lie in the domain (a log of a ball containing 0, an asin of a ball reaching beyond \pm 1, a tangent of a ball that may contain a pole). The functions without a status throw where the result's exponent would leave the safe range: \exp(y) for |y| \ge 2^{\mathtt{FLINT\_BITS} - 5}. - Aliasing. Outputs may alias the argument. Where a function has two outputs (
mp_real_sin_cos_bits,mp_real_sinh_cosh_bits), either may beNULL. - Huge arguments. The sine, cosine and tangent give [0 \pm 1], resp. status 0, for |x| \ge 2^{\max(65536,\, 4\,\mathit{prec})}, where the reduction modulo \pi/2 would need more bits of \pi than is reasonable.
The functions with explicit precisions in limbs, mp_real_sin_cos_pi_ui_div_ui, mp_real_tan_pi_ui_div_ui and the table-free exponentials, follow the same conventions with B^{-n} in place of 2^{-\mathit{prec}}.
Algorithms#
Each function reduces the argument to a fixed-point number in [0, 1) (by \log 2 for exp, by the exponent for log, by \pi/2 for the trigonometric functions, exactly by 1/2 for the functions of \pi x, and to |x| < 1 for atan) and calls the kernel for the working size: table-driven kernels up to three limbs, dense-table kernels up to 32 limbs, bitwise reduction up to 600 limbs, multi-prime (diophantine) reduction up to 65536 limbs (Newton–Taylor inversion of it for log and atan), and table-free bit-burst evaluation beyond. The hyperbolic and inverse functions are compositions of exp, log and atan arranged to avoid cancellation. The guide Fixed-point kernels lists the kernels, and Elementary functions in mp_real describes them.
AlgorithmElementary functions in mp_realHow mp_real evaluates exp, log, the trigonometric functions and their inverses from one limb to millions of limbs: argument reduction of balls, table-driven and dense-table kernels, bitwise (BKM-type) reduction with signed digits, rectangular splitting, bit-burst evaluation, Newton–Taylor inversion, the AGM logarithm, and sines of rational multiples of π.Example#
#include <flint/flint.h>
#include <flint/mp_real.h>
#include <flint/arb.h>
static void show(const char * name, const mp_real_t x)
{
arb_t a;
arb_init(a);
mp_real_get_arb(a, x);
flint_printf("%s = ", name);
arb_printn(a, 30, 0);
flint_printf("\n");
arb_clear(a);
}
int main(void)
{
mp_real_t x, s, c, y;
int ok;
mp_real_init(x);
mp_real_init(s);
mp_real_init(c);
mp_real_init(y);
/* x = 3/2 exactly */
mp_real_set_ui(x, 3);
mp_real_mul_2exp_si(x, x, -1);
mp_real_exp_bits(y, x, 100);
show("exp(3/2)", y);
mp_real_log_bits(y, x, 100);
show("log(3/2)", y);
mp_real_sin_cos_bits(s, c, x, 100);
show("sin(3/2)", s);
show("cos(3/2)", c);
ok = mp_real_tan_bits(y, x, 100);
flint_printf("tan status %d\n", ok);
show("tan(3/2)", y);
/* x = 1/2 + 2^-200: cos(pi x) keeps its relative accuracy */
mp_real_set_ui(x, 1);
mp_real_mul_2exp_si(x, x, -200);
mp_real_set_ui(y, 1);
mp_real_mul_2exp_si(y, y, -1);
mp_real_add(x, x, y, 10);
mp_real_sin_cos_pi_bits(s, c, x, 100);
show("sin(pi x)", s);
show("cos(pi x)", c);
/* a ball containing 0 is outside the domain of log */
mp_real_set_si(x, -1);
mp_real_add_error_2exp_si(x, 1);
ok = mp_real_log_bits(y, x, 100);
flint_printf("log status %d\n", ok);
mp_real_set_ui(x, 1);
mp_real_mul_2exp_si(x, x, -1);
mp_real_atanh_bits(y, x, 100);
show("atanh(1/2)", y);
mp_real_clear(x);
mp_real_clear(s);
mp_real_clear(c);
mp_real_clear(y);
flint_cleanup_master();
return 0;
}exp(3/2) = [4.48168907033806482260205546012 +/- 7.25e-31] log(3/2) = [0.405465108108164381978013115464 +/- 3.50e-31] sin(3/2) = [0.997494986604054430941723371141 +/- 4.88e-31] cos(3/2) = [0.0707372016677029100881898514343 +/- 3.13e-32] tan status 1 tan(3/2) = [14.1014199471717193876460836520 +/- 1.23e-29] sin(pi x) = [1.00000000000000000000000000000 +/- 4.64e-69] cos(pi x) = [-1.95501790801056086750878985681e-60 +/- 9.48e-93] log status 0 atanh(1/2) = [0.549306144334054845697622618461 +/- 2.63e-31]
The value \cos(\pi(1/2 + 2^{-200})) = -\sin(\pi 2^{-200}) is about -\pi \cdot 2^{-200} and is computed with a relative error of about 2^{-106}, although the argument itself has 200 bits.
Guides#
The FLINT team, “Elementary functions of balls (mp_real.h),” FLINT: Fast Library for Number Theory, documentation, version 3.7.0-dev, 2026. https://flintlib.org/doc/mp_real/elementary.html (generated 2026-10-20).
@misc{flint-doc-mp-real-elementary,
author = {{The FLINT team}},
title = {{Elementary functions of balls (mp\_real.h)}},
howpublished = {FLINT: Fast Library for Number Theory, documentation, version 3.7.0-dev},
year = {2026},
url = {https://flintlib.org/doc/mp_real/elementary.html},
note = {Generated 2026-10-20}
}