.. _mag: **mag.h** -- fixed-precision unsigned floating-point numbers for bounds =============================================================================== The :type:`mag_t` type holds an unsigned floating-point number with a fixed-precision mantissa (30 bits) and an arbitrary-precision exponent (represented as an :type:`fmpz_t`), suited for representing magnitude bounds. The special values zero and positive infinity are supported, but not NaN. Operations that involve rounding will always produce a valid upper bound, or a lower bound if the function name has the suffix *lower*. For performance reasons, no attempt is made to compute the best possible bounds: in general, a bound may be several ulps larger/smaller than the optimal bound. Some functions such as :func:`mag_set` and :func:`mag_mul_2exp_si` are always exact and therefore do not require separate *lower* versions. A common mistake is to forget computing a lower bound for the argument of a decreasing function that is meant to be bounded from above, or vice versa. For example, to compute an upper bound for `(x+1)/(y+1)`, the parameter *x* should initially be an upper bound while *y* should be a lower bound, and one should do:: mag_add_ui(tmp1, x, 1); mag_add_ui_lower(tmp2, y, 1); mag_div(res, tmp1, tmp2); For a lower bound of the same expression, *x* should be a lower bound while *y* should be an upper bound, and one should do:: mag_add_ui_lower(tmp1, x, 1); mag_add_ui(tmp2, y, 1); mag_div_lower(res, tmp1, tmp2); Applications requiring floating-point arithmetic with more flexibility (such as correct rounding, or higher precision) should use the :type:`arf_t` type instead. For calculations where a complex alternation between upper and lower bounds is necessary, it may be cleaner to use :type:`arb_t` arithmetic and convert to a :type:`mag_t` bound only in the end. Types, macros and constants ------------------------------------------------------------------------------- .. type:: mag_struct A :type:`mag_struct` holds a mantissa and an exponent. Special values are encoded by the mantissa being set to zero. .. type:: mag_t A :type:`mag_t` is defined as an array of length one of type :type:`mag_struct`, permitting a :type:`mag_t` to be passed by reference. Memory management ------------------------------------------------------------------------------- .. function:: void mag_init(mag_t x) Initializes the variable *x* for use. Its value is set to zero. .. function:: void mag_clear(mag_t x) Clears the variable *x*, freeing or recycling its allocated memory. .. function:: void mag_swap(mag_t x, mag_t y) Swaps *x* and *y* efficiently. .. function:: mag_ptr _mag_vec_init(slong n) Allocates a vector of length *n*. All entries are set to zero. .. function:: void _mag_vec_clear(mag_ptr v, slong n) Clears a vector of length *n*. .. function:: slong mag_allocated_bytes(const mag_t x) Returns the total number of bytes heap-allocated internally by this object. The count excludes the size of the structure itself. Add ``sizeof(mag_struct)`` to get the size of the object as a whole. Special values ------------------------------------------------------------------------------- .. function:: void mag_zero(mag_t res) Sets *res* to zero. .. function:: void mag_one(mag_t res) Sets *res* to one. .. function:: void mag_inf(mag_t res) Sets *res* to positive infinity. .. function:: int mag_is_special(const mag_t x) Returns nonzero iff *x* is zero or positive infinity. .. function:: int mag_is_zero(const mag_t x) Returns nonzero iff *x* is zero. .. function:: int mag_is_inf(const mag_t x) Returns nonzero iff *x* is positive infinity. .. function:: int mag_is_finite(const mag_t x) Returns nonzero iff *x* is not positive infinity (since there is no NaN value, this function is exactly the logical negation of :func:`mag_is_inf`). Assignment and conversions ------------------------------------------------------------------------------- .. function:: void mag_init_set(mag_t res, const mag_t x) Initializes *res* and sets it to the value of *x*. This operation is always exact. .. function:: void mag_set(mag_t res, const mag_t x) Sets *res* to the value of *x*. This operation is always exact. .. function:: void mag_set_d(mag_t res, double x) .. function:: void mag_set_fmpr(mag_t res, const fmpr_t x) .. function:: void mag_set_ui(mag_t res, ulong x) .. function:: void mag_set_fmpz(mag_t res, const fmpz_t x) Sets *res* to an upper bound for `|x|`. The operation may be inexact even if *x* is exactly representable. .. function:: void mag_set_d_lower(mag_t res, double x) .. function:: void mag_set_ui_lower(mag_t res, ulong x) .. function:: void mag_set_fmpz_lower(mag_t res, const fmpz_t x) Sets *res* to a lower bound for `|x|`. The operation may be inexact even if *x* is exactly representable. .. function:: void mag_set_d_2exp_fmpz(mag_t res, double x, const fmpz_t y) .. function:: void mag_set_fmpz_2exp_fmpz(mag_t res, const fmpz_t x, const fmpz_t y) .. function:: void mag_set_ui_2exp_si(mag_t res, ulong x, slong y) Sets *res* to an upper bound for `|x| \cdot 2^y`. .. function:: void mag_set_d_2exp_fmpz_lower(mag_t res, double x, const fmpz_t y) .. function:: void mag_set_fmpz_2exp_fmpz_lower(mag_t res, const fmpz_t x, const fmpz_t y) Sets *res* to a lower bound for `|x| \cdot 2^y`. .. function:: double mag_get_d(const mag_t x) Returns a *double* giving an upper bound for *x*. .. function:: double mag_get_d_log2_approx(const mag_t x) Returns a *double* approximating `\log_2(x)`, suitable for estimating magnitudes (warning: not a rigorous bound). The value is clamped between *COEFF_MIN* and *COEFF_MAX*. .. function:: void mag_get_fmpr(fmpr_t res, const mag_t x) Sets *res* exactly to *x*. .. function:: void mag_get_fmpq(fmpq_t res, const mag_t x) .. function:: void mag_get_fmpz(fmpz_t res, const mag_t x) .. function:: void mag_get_fmpz_lower(fmpz_t res, const mag_t x) Sets *res*, respectively, to the exact rational number represented by *x*, the integer exactly representing the ceiling function of *x*, or the integer exactly representing the floor function of *x*. These functions are unsafe: the user must check in advance that *x* is of reasonable magnitude. If *x* is infinite or has a bignum exponent, an abort will be raised. If the exponent otherwise is too large or too small, the available memory could be exhausted resulting in undefined behavior. Comparisons ------------------------------------------------------------------------------- .. function:: int mag_equal(const mag_t x, const mag_t y) Returns nonzero iff *x* and *y* have the same value. .. function:: int mag_cmp(const mag_t x, const mag_t y) Returns negative, zero, or positive, depending on whether *x* is smaller, equal, or larger than *y*. .. function:: int mag_cmp_2exp_si(const mag_t x, slong y) Returns negative, zero, or positive, depending on whether *x* is smaller, equal, or larger than `2^y`. .. function:: void mag_min(mag_t res, const mag_t x, const mag_t y) .. function:: void mag_max(mag_t res, const mag_t x, const mag_t y) Sets *res* respectively to the smaller or the larger of *x* and *y*. Input and output ------------------------------------------------------------------------------- .. function:: void mag_print(const mag_t x) Prints *x* to standard output. .. function:: void mag_fprint(FILE * file, const mag_t x) Prints *x* to the stream *file*. .. function:: char * mag_dump_str(const mag_t x) Allocates a string and writes a binary representation of *x* to it that can be read by :func:`mag_load_str`. The returned string needs to be deallocated with *flint_free*. .. function:: int mag_load_str(mag_t x, const char * str) Parses *str* into *x*. Returns a nonzero value if *str* is not formatted correctly. .. function:: int mag_dump_file(FILE * stream, const mag_t x) Writes a binary representation of *x* to *stream* that can be read by :func:`mag_load_file`. Returns a nonzero value if the data could not be written. .. function:: int mag_load_file(mag_t x, FILE * stream) Reads *x* from *stream*. Returns a nonzero value if the data is not formatted correctly or the read failed. Note that the data is assumed to be delimited by a whitespace or end-of-file, i.e., when writing multiple values with :func:`mag_dump_file` make sure to insert a whitespace to separate consecutive values. Random generation ------------------------------------------------------------------------------- .. function:: void mag_randtest(mag_t res, flint_rand_t state, slong expbits) Sets *res* to a random finite value, with an exponent up to *expbits* bits large. .. function:: void mag_randtest_special(mag_t res, flint_rand_t state, slong expbits) Like :func:`mag_randtest`, but also sometimes sets *res* to infinity. Arithmetic ------------------------------------------------------------------------------- .. function:: void mag_add(mag_t res, const mag_t x, const mag_t y) .. function:: void mag_add_ui(mag_t res, const mag_t x, ulong y) Sets *res* to an upper bound for `x + y`. .. function:: void mag_add_lower(mag_t res, const mag_t x, const mag_t y) .. function:: void mag_add_ui_lower(mag_t res, const mag_t x, ulong y) Sets *res* to a lower bound for `x + y`. .. function:: void mag_add_2exp_fmpz(mag_t res, const mag_t x, const fmpz_t e) Sets *res* to an upper bound for `x + 2^e`. .. function:: void mag_add_ui_2exp_si(mag_t res, const mag_t x, ulong y, slong e) Sets *res* to an upper bound for `x + y 2^e`. .. function:: void mag_sub(mag_t res, const mag_t x, const mag_t y) Sets *res* to an upper bound for `\max(x-y, 0)`. .. function:: void mag_sub_lower(mag_t res, const mag_t x, const mag_t y) Sets *res* to a lower bound for `\max(x-y, 0)`. .. function:: void mag_mul_2exp_si(mag_t res, const mag_t x, slong y) .. function:: void mag_mul_2exp_fmpz(mag_t res, const mag_t x, const fmpz_t y) Sets *res* to `x \cdot 2^y`. This operation is exact. .. function:: void mag_mul(mag_t res, const mag_t x, const mag_t y) .. function:: void mag_mul_ui(mag_t res, const mag_t x, ulong y) .. function:: void mag_mul_fmpz(mag_t res, const mag_t x, const fmpz_t y) Sets *res* to an upper bound for `xy`. .. function:: void mag_mul_lower(mag_t res, const mag_t x, const mag_t y) .. function:: void mag_mul_ui_lower(mag_t res, const mag_t x, ulong y) .. function:: void mag_mul_fmpz_lower(mag_t res, const mag_t x, const fmpz_t y) Sets *res* to a lower bound for `xy`. .. function:: void mag_addmul(mag_t z, const mag_t x, const mag_t y) Sets *z* to an upper bound for `z + xy`. .. function:: void mag_div(mag_t res, const mag_t x, const mag_t y) .. function:: void mag_div_ui(mag_t res, const mag_t x, ulong y) .. function:: void mag_div_fmpz(mag_t res, const mag_t x, const fmpz_t y) Sets *res* to an upper bound for `x / y`. .. function:: void mag_div_lower(mag_t res, const mag_t x, const mag_t y) Sets *res* to a lower bound for `x / y`. .. function:: void mag_inv(mag_t res, const mag_t x) Sets *res* to an upper bound for `1 / x`. .. function:: void mag_inv_lower(mag_t res, const mag_t x) Sets *res* to a lower bound for `1 / x`. Fast, unsafe arithmetic ------------------------------------------------------------------------------- The following methods assume that all inputs are finite and that all exponents (in all inputs as well as the final result) fit as *fmpz* inline values. They also assume that the output variables do not have promoted exponents, as they will be overwritten directly (thus leaking memory). .. function:: void mag_fast_init_set(mag_t x, const mag_t y) Initialises *x* and sets it to the value of *y*. .. function:: void mag_fast_zero(mag_t res) Sets *res* to zero. .. function:: int mag_fast_is_zero(const mag_t x) Returns nonzero iff *x* to zero. .. function:: void mag_fast_mul(mag_t res, const mag_t x, const mag_t y) Sets *res* to an upper bound for `xy`. .. function:: void mag_fast_addmul(mag_t z, const mag_t x, const mag_t y) Sets *z* to an upper bound for `z + xy`. .. function:: void mag_fast_add_2exp_si(mag_t res, const mag_t x, slong e) Sets *res* to an upper bound for `x + 2^e`. .. function:: void mag_fast_mul_2exp_si(mag_t res, const mag_t x, slong e) Sets *res* to an upper bound for `x 2^e`. Powers and logarithms ------------------------------------------------------------------------------- .. function:: void mag_pow_ui(mag_t res, const mag_t x, ulong e) .. function:: void mag_pow_fmpz(mag_t res, const mag_t x, const fmpz_t e) Sets *res* to an upper bound for `x^e`. .. function:: void mag_pow_ui_lower(mag_t res, const mag_t x, ulong e) .. function:: void mag_pow_fmpz_lower(mag_t res, const mag_t x, const fmpz_t e) Sets *res* to a lower bound for `x^e`. .. function:: void mag_sqrt(mag_t res, const mag_t x) Sets *res* to an upper bound for `\sqrt{x}`. .. function:: void mag_sqrt_lower(mag_t res, const mag_t x) Sets *res* to a lower bound for `\sqrt{x}`. .. function:: void mag_rsqrt(mag_t res, const mag_t x) Sets *res* to an upper bound for `1/\sqrt{x}`. .. function:: void mag_rsqrt_lower(mag_t res, const mag_t x) Sets *res* to an lower bound for `1/\sqrt{x}`. .. function:: void mag_hypot(mag_t res, const mag_t x, const mag_t y) Sets *res* to an upper bound for `\sqrt{x^2 + y^2}`. .. function:: void mag_root(mag_t res, const mag_t x, ulong n) Sets *res* to an upper bound for `x^{1/n}`. .. function:: void mag_log(mag_t res, const mag_t x) Sets *res* to an upper bound for `\log(\max(1,x))`. .. function:: void mag_log_lower(mag_t res, const mag_t x) Sets *res* to a lower bound for `\log(\max(1,x))`. .. function:: void mag_neg_log(mag_t res, const mag_t x) Sets *res* to an upper bound for `-\log(\min(1,x))`, i.e. an upper bound for `|\log(x)|` for `x \le 1`. .. function:: void mag_neg_log_lower(mag_t res, const mag_t x) Sets *res* to a lower bound for `-\log(\min(1,x))`, i.e. a lower bound for `|\log(x)|` for `x \le 1`. .. function:: void mag_log_ui(mag_t res, ulong n) Sets *res* to an upper bound for `\log(n)`. .. function:: void mag_log1p(mag_t res, const mag_t x) Sets *res* to an upper bound for `\log(1+x)`. The bound is computed accurately for small *x*. .. function:: void mag_exp(mag_t res, const mag_t x) Sets *res* to an upper bound for `\exp(x)`. .. function:: void mag_exp_lower(mag_t res, const mag_t x) Sets *res* to a lower bound for `\exp(x)`. .. function:: void mag_expinv(mag_t res, const mag_t x) Sets *res* to an upper bound for `\exp(-x)`. .. function:: void mag_expinv_lower(mag_t res, const mag_t x) Sets *res* to a lower bound for `\exp(-x)`. .. function:: void mag_expm1(mag_t res, const mag_t x) Sets *res* to an upper bound for `\exp(x) - 1`. The bound is computed accurately for small *x*. .. function:: void mag_exp_tail(mag_t res, const mag_t x, ulong N) Sets *res* to an upper bound for `\sum_{k=N}^{\infty} x^k / k!`. .. function:: void mag_binpow_uiui(mag_t res, ulong m, ulong n) Sets *res* to an upper bound for `(1 + 1/m)^n`. .. function:: void mag_geom_series(mag_t res, const mag_t x, ulong N) Sets *res* to an upper bound for `\sum_{k=N}^{\infty} x^k`. Special functions ------------------------------------------------------------------------------- .. function:: void mag_const_pi(mag_t res) .. function:: void mag_const_pi_lower(mag_t res) Sets *res* to an upper (respectively lower) bound for `\pi`. .. function:: void mag_atan(mag_t res, const mag_t x) .. function:: void mag_atan_lower(mag_t res, const mag_t x) Sets *res* to an upper (respectively lower) bound for `\operatorname{atan}(x)`. .. function:: void mag_cosh(mag_t res, const mag_t x) .. function:: void mag_cosh_lower(mag_t res, const mag_t x) .. function:: void mag_sinh(mag_t res, const mag_t x) .. function:: void mag_sinh_lower(mag_t res, const mag_t x) Sets *res* to an upper or lower bound for `\cosh(x)` or `\sinh(x)`. .. function:: void mag_fac_ui(mag_t res, ulong n) Sets *res* to an upper bound for `n!`. .. function:: void mag_rfac_ui(mag_t res, ulong n) Sets *res* to an upper bound for `1/n!`. .. function:: void mag_bin_uiui(mag_t res, ulong n, ulong k) Sets *res* to an upper bound for the binomial coefficient `{n \choose k}`. .. function:: void mag_bernoulli_div_fac_ui(mag_t res, ulong n) Sets *res* to an upper bound for `|B_n| / n!` where `B_n` denotes a Bernoulli number. .. function:: void mag_polylog_tail(mag_t res, const mag_t z, slong s, ulong d, ulong N) Sets *res* to an upper bound for .. math :: \sum_{k=N}^{\infty} \frac{z^k \log^d(k)}{k^s}. The bounding strategy is described in :ref:`algorithms_polylogarithms`. Note: in applications where `s` in this formula may be real or complex, the user can simply substitute any convenient integer `s'` such that `s' \le \operatorname{Re}(s)`. .. function:: void mag_hurwitz_zeta_uiui(mag_t res, ulong s, ulong a) Sets *res* to an upper bound for `\zeta(s,a) = \sum_{k=0}^{\infty} (k+a)^{-s}`. We use the formula .. math :: \zeta(s,a) \le \frac{1}{a^s} + \frac{1}{(s-1) a^{s-1}} which is obtained by estimating the sum by an integral. If `s \le 1` or `a = 0`, the bound is infinite.