arb/doc/source/mag.rst

540 lines
17 KiB
ReStructuredText
Raw Normal View History

2014-05-08 14:48:36 +02:00
.. _mag:
**mag.h** -- fixed-precision unsigned floating-point numbers for bounds
===============================================================================
The :type:`mag_t` type holds an unsigned floating-point number with a
2014-05-08 19:35:52 +02:00
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,
2020-03-13 13:32:20 +01:00
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.
2014-05-08 14:48:36 +02:00
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)
2014-06-20 09:27:47 +02:00
Swaps *x* and *y* efficiently.
2015-11-06 11:51:57 +00:00
.. function:: mag_ptr _mag_vec_init(slong n)
2014-06-20 09:27:47 +02:00
Allocates a vector of length *n*. All entries are set to zero.
2015-11-06 11:51:57 +00:00
.. function:: void _mag_vec_clear(mag_ptr v, slong n)
2014-06-20 09:27:47 +02:00
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.
2014-05-08 14:48:36 +02:00
Special values
-------------------------------------------------------------------------------
.. function:: void mag_zero(mag_t res)
2014-05-08 14:48:36 +02:00
Sets *res* to zero.
2014-05-08 14:48:36 +02:00
.. function:: void mag_one(mag_t res)
Sets *res* to one.
.. function:: void mag_inf(mag_t res)
2014-05-08 14:48:36 +02:00
Sets *res* to positive infinity.
2014-05-08 14:48:36 +02:00
.. 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)
2014-09-25 15:06:11 +02:00
.. function:: void mag_set_fmpz(mag_t res, const fmpz_t x)
2014-09-25 15:06:11 +02:00
Sets *res* to an upper bound for `|x|`. The operation may be inexact
even if *x* is exactly representable.
2014-09-25 15:06:11 +02:00
.. function:: void mag_set_d_lower(mag_t res, double x)
2014-08-14 22:09:50 +02:00
.. function:: void mag_set_ui_lower(mag_t res, ulong x)
2014-08-14 22:09:50 +02:00
.. function:: void mag_set_fmpz_lower(mag_t res, const fmpz_t x)
2014-08-14 22:09:50 +02:00
Sets *res* to a lower bound for `|x|`.
The operation may be inexact even if *x* is exactly representable.
2015-12-31 18:26:05 -05:00
.. function:: void mag_set_d_2exp_fmpz(mag_t res, double x, const fmpz_t y)
2015-12-31 18:26:05 -05:00
.. function:: void mag_set_fmpz_2exp_fmpz(mag_t res, const fmpz_t x, const fmpz_t y)
2014-08-14 22:09:50 +02:00
.. function:: void mag_set_ui_2exp_si(mag_t res, ulong x, slong y)
2014-08-14 22:09:50 +02:00
Sets *res* to an upper bound for `|x| \cdot 2^y`.
2014-08-14 22:09:50 +02:00
.. function:: void mag_set_d_2exp_fmpz_lower(mag_t res, double x, const fmpz_t y)
2014-08-14 22:09:50 +02:00
.. function:: void mag_set_fmpz_2exp_fmpz_lower(mag_t res, const fmpz_t x, const fmpz_t y)
2014-08-14 22:09:50 +02:00
Sets *res* to a lower bound for `|x| \cdot 2^y`.
2014-08-14 22:09:50 +02:00
.. function:: double mag_get_d(const mag_t x)
2014-08-14 22:09:50 +02:00
Returns a *double* giving an upper bound for *x*.
2014-08-14 22:09:50 +02:00
.. function:: double mag_get_d_log2_approx(const mag_t x)
2014-08-14 22:09:50 +02:00
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*.
2014-08-14 22:09:50 +02:00
.. function:: void mag_get_fmpr(fmpr_t res, const mag_t x)
2014-08-14 22:09:50 +02:00
Sets *res* exactly to *x*.
2014-08-14 22:09:50 +02:00
.. function:: void mag_get_fmpq(fmpq_t res, const mag_t x)
2014-08-14 22:09:50 +02:00
.. function:: void mag_get_fmpz(fmpz_t res, const mag_t x)
2014-08-14 22:09:50 +02:00
.. function:: void mag_get_fmpz_lower(fmpz_t res, const mag_t x)
2014-08-14 22:09:50 +02:00
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.
2014-08-14 22:09:50 +02:00
.. function:: int mag_cmp(const mag_t x, const mag_t y)
2014-08-14 22:09:50 +02:00
Returns negative, zero, or positive, depending on whether *x*
is smaller, equal, or larger than *y*.
2014-08-14 22:09:50 +02:00
.. 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*.
2014-08-14 22:09:50 +02:00
Input and output
-------------------------------------------------------------------------------
2016-03-21 21:41:48 +01:00
.. function:: void mag_print(const mag_t x)
2016-03-21 21:41:48 +01:00
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
-------------------------------------------------------------------------------
2014-08-14 22:09:50 +02:00
.. function:: void mag_randtest(mag_t res, flint_rand_t state, slong expbits)
2014-08-14 22:09:50 +02:00
Sets *res* to a random finite value, with an exponent up to *expbits* bits large.
2014-08-14 22:09:50 +02:00
.. function:: void mag_randtest_special(mag_t res, flint_rand_t state, slong expbits)
2014-08-14 22:09:50 +02:00
Like :func:`mag_randtest`, but also sometimes sets *res* to infinity.
2014-08-14 22:09:50 +02:00
2014-05-08 14:48:36 +02:00
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)
2014-05-08 14:48:36 +02:00
.. function:: void mag_add_ui_lower(mag_t res, const mag_t x, ulong y)
2014-06-20 09:27:47 +02:00
Sets *res* to a lower bound for `x + y`.
2014-06-20 09:27:47 +02:00
.. function:: void mag_add_2exp_fmpz(mag_t res, const mag_t x, const fmpz_t e)
2014-06-20 09:27:47 +02:00
Sets *res* to an upper bound for `x + 2^e`.
2014-06-20 09:27:47 +02:00
.. 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`.
2014-05-08 14:48:36 +02:00
.. function:: void mag_sub(mag_t res, const mag_t x, const mag_t y)
2014-05-08 14:48:36 +02:00
Sets *res* to an upper bound for `\max(x-y, 0)`.
2014-05-08 14:48:36 +02:00
.. function:: void mag_sub_lower(mag_t res, const mag_t x, const mag_t y)
2014-05-08 14:48:36 +02:00
Sets *res* to a lower bound for `\max(x-y, 0)`.
2014-05-08 14:48:36 +02:00
.. 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.
2014-05-08 14:48:36 +02:00
.. function:: void mag_mul(mag_t res, const mag_t x, const mag_t y)
2014-06-20 09:27:47 +02:00
.. function:: void mag_mul_ui(mag_t res, const mag_t x, ulong y)
2014-06-20 09:27:47 +02:00
.. function:: void mag_mul_fmpz(mag_t res, const mag_t x, const fmpz_t y)
2014-06-20 09:27:47 +02:00
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)
2014-06-20 09:27:47 +02:00
.. function:: void mag_div_ui(mag_t res, const mag_t x, ulong y)
2014-06-20 09:27:47 +02:00
.. function:: void mag_div_fmpz(mag_t res, const mag_t x, const fmpz_t y)
2014-06-20 09:27:47 +02:00
Sets *res* to an upper bound for `x / y`.
2014-06-20 09:27:47 +02:00
.. function:: void mag_div_lower(mag_t res, const mag_t x, const mag_t y)
2014-06-20 09:27:47 +02:00
Sets *res* to a lower bound for `x / y`.
2014-06-20 09:27:47 +02:00
.. function:: void mag_inv(mag_t res, const mag_t x)
2016-03-14 02:05:07 +01:00
Sets *res* to an upper bound for `1 / x`.
2016-03-14 02:05:07 +01:00
.. function:: void mag_inv_lower(mag_t res, const mag_t x)
Sets *res* to a lower bound for `1 / x`.
2014-08-14 22:09:50 +02:00
Fast, unsafe arithmetic
2014-05-08 14:48:36 +02:00
-------------------------------------------------------------------------------
2014-05-08 19:35:52 +02:00
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).
2014-05-08 14:48:36 +02:00
.. function:: void mag_fast_init_set(mag_t x, const mag_t y)
2014-05-08 19:35:52 +02:00
Initialises *x* and sets it to the value of *y*.
.. function:: void mag_fast_zero(mag_t res)
2014-05-08 14:48:36 +02:00
Sets *res* to zero.
2014-05-08 19:35:52 +02:00
2014-05-08 14:48:36 +02:00
.. function:: int mag_fast_is_zero(const mag_t x)
2014-05-08 19:35:52 +02:00
Returns nonzero iff *x* to zero.
2014-05-08 14:48:36 +02:00
.. function:: void mag_fast_mul(mag_t res, const mag_t x, const mag_t y)
2014-05-08 14:48:36 +02:00
Sets *res* to an upper bound for `xy`.
2014-05-08 19:35:52 +02:00
2014-05-08 14:48:36 +02:00
.. function:: void mag_fast_addmul(mag_t z, const mag_t x, const mag_t y)
2014-06-20 09:27:47 +02:00
Sets *z* to an upper bound for `z + xy`.
2014-05-08 19:35:52 +02:00
.. function:: void mag_fast_add_2exp_si(mag_t res, const mag_t x, slong e)
2014-05-08 14:48:36 +02:00
Sets *res* to an upper bound for `x + 2^e`.
2014-05-08 19:35:52 +02:00
.. 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`.
2014-08-14 22:09:50 +02:00
Powers and logarithms
2014-05-08 14:48:36 +02:00
-------------------------------------------------------------------------------
.. 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`. Requires `e \ge 0`.
2014-05-08 14:48:36 +02:00
.. function:: void mag_pow_ui_lower(mag_t res, const mag_t x, ulong e)
2014-05-08 14:48:36 +02:00
.. 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`. Requires `e \ge 0`.
2014-05-08 14:48:36 +02:00
.. 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)
2014-05-08 14:48:36 +02:00
Sets *res* to an upper bound for `1/\sqrt{x}`.
2014-06-20 09:27:47 +02:00
.. 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)
2014-12-20 22:37:43 +01:00
Sets *res* to an upper bound for `\sqrt{x^2 + y^2}`.
2014-12-20 22:37:43 +01:00
.. function:: void mag_root(mag_t res, const mag_t x, ulong n)
2015-07-21 15:09:06 +02:00
Sets *res* to an upper bound for `x^{1/n}`.
2015-07-21 15:09:06 +02:00
.. function:: void mag_log(mag_t res, const mag_t x)
2014-06-20 09:27:47 +02:00
Sets *res* to an upper bound for `\log(\max(1,x))`.
2014-06-20 09:27:47 +02:00
.. 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)
2014-06-20 09:27:47 +02:00
Sets *res* to an upper bound for `\exp(x)`.
2014-06-20 09:27:47 +02:00
.. 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)
2016-03-14 02:05:07 +01:00
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)`.
2016-03-14 02:05:07 +01:00
.. function:: void mag_expm1(mag_t res, const mag_t x)
2014-09-25 15:06:11 +02:00
Sets *res* to an upper bound for `\exp(x) - 1`. The bound is computed
2014-09-25 15:06:11 +02:00
accurately for small *x*.
.. function:: void mag_exp_tail(mag_t res, const mag_t x, ulong N)
2014-08-15 13:21:02 +02:00
Sets *res* to an upper bound for `\sum_{k=N}^{\infty} x^k / k!`.
2014-08-15 13:21:02 +02:00
.. function:: void mag_binpow_uiui(mag_t res, ulong m, ulong n)
Sets *res* to an upper bound for `(1 + 1/m)^n`.
2015-09-17 12:51:02 +02:00
.. 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`.
2014-06-20 09:27:47 +02:00
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)
2014-06-20 09:27:47 +02:00
Sets *res* to an upper bound for `n!`.
2014-06-20 09:27:47 +02:00
.. function:: void mag_rfac_ui(mag_t res, ulong n)
2014-06-20 09:27:47 +02:00
Sets *res* to an upper bound for `1/n!`.
2014-06-20 09:27:47 +02:00
2017-10-06 20:07:41 +02:00
.. 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)
2014-06-20 09:27:47 +02:00
Sets *res* to an upper bound for `|B_n| / n!` where `B_n` denotes
2014-06-20 09:27:47 +02:00
a Bernoulli number.
.. function:: void mag_polylog_tail(mag_t res, const mag_t z, slong s, ulong d, ulong N)
2015-01-16 09:29:10 +01:00
Sets *res* to an upper bound for
2015-01-16 09:29:10 +01:00
.. math ::
\sum_{k=N}^{\infty} \frac{z^k \log^d(k)}{k^s}.
The bounding strategy is described in :ref:`algorithms_polylogarithms`.
2015-01-16 09:29:10 +01:00
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)`.
2016-01-13 15:38:44 +01:00
.. 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 ::
2016-01-13 17:55:31 +01:00
\zeta(s,a) \le \frac{1}{a^s} + \frac{1}{(s-1) a^{s-1}}
2016-01-13 15:38:44 +01:00
which is obtained by estimating the sum by an integral.
If `s \le 1` or `a = 0`, the bound is infinite.