mirror of
https://github.com/vale981/arb
synced 2025-03-06 01:41:39 -05:00
rewrite arb_get_unique_fmpz and arb_get_interval_fmpz_2exp, reducing overhead, making them more robust with huge exponents, and documenting this more carefully
This commit is contained in:
parent
8c5d26de65
commit
7cebb85b15
6 changed files with 288 additions and 65 deletions
|
@ -28,9 +28,79 @@
|
|||
void
|
||||
arb_get_interval_fmpz_2exp(fmpz_t a, fmpz_t b, fmpz_t exp, const arb_t x)
|
||||
{
|
||||
fmprb_t t;
|
||||
fmprb_init(t);
|
||||
arb_get_fmprb(t, x);
|
||||
fmprb_get_interval_fmpz_2exp(a, b, exp, t);
|
||||
fmprb_clear(t);
|
||||
if (!arb_is_finite(x))
|
||||
{
|
||||
printf("arb_get_interval_fmpz_2exp: expected finite input\n");
|
||||
abort();
|
||||
}
|
||||
else if (arb_is_exact(x))
|
||||
{
|
||||
arf_get_fmpz_2exp(a, exp, arb_midref(x));
|
||||
fmpz_set(b, a);
|
||||
}
|
||||
else if (arf_is_zero(arb_midref(x)))
|
||||
{
|
||||
arf_t t;
|
||||
arf_init_set_mag_shallow(t, arb_radref(x));
|
||||
arf_get_fmpz_2exp(b, exp, t);
|
||||
fmpz_neg(a, b);
|
||||
}
|
||||
else
|
||||
{
|
||||
arf_t rad;
|
||||
fmpz_t tmp;
|
||||
slong shift;
|
||||
mp_bitcnt_t aval, bval;
|
||||
|
||||
fmpz_init(tmp);
|
||||
|
||||
arf_get_fmpz_2exp(a, exp, arb_midref(x));
|
||||
arf_init_set_mag_shallow(rad, arb_radref(x));
|
||||
arf_get_fmpz_2exp(b, tmp, rad);
|
||||
|
||||
shift = _fmpz_sub_small(exp, tmp);
|
||||
|
||||
if (FLINT_ABS(shift) >= WORD_MAX / 2)
|
||||
{
|
||||
printf("arb_get_interval_fmpz_2exp: too large shift\n");
|
||||
abort();
|
||||
}
|
||||
|
||||
if (shift >= 0)
|
||||
{
|
||||
fmpz_mul_2exp(a, a, shift);
|
||||
fmpz_set(exp, tmp);
|
||||
}
|
||||
else
|
||||
fmpz_mul_2exp(b, b, -shift);
|
||||
|
||||
fmpz_sub(tmp, a, b);
|
||||
fmpz_add(b, a, b);
|
||||
fmpz_swap(tmp, a);
|
||||
|
||||
if (fmpz_is_zero(a))
|
||||
{
|
||||
aval = fmpz_val2(b);
|
||||
}
|
||||
else if (fmpz_is_zero(b))
|
||||
{
|
||||
aval = fmpz_val2(a);
|
||||
}
|
||||
else
|
||||
{
|
||||
aval = fmpz_val2(a);
|
||||
bval = fmpz_val2(b);
|
||||
aval = FLINT_MIN(aval, bval);
|
||||
}
|
||||
|
||||
if (aval > 0)
|
||||
{
|
||||
fmpz_add_ui(exp, exp, aval);
|
||||
fmpz_tdiv_q_2exp(a, a, aval);
|
||||
fmpz_tdiv_q_2exp(b, b, aval);
|
||||
}
|
||||
|
||||
fmpz_clear(tmp);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
=============================================================================*/
|
||||
/******************************************************************************
|
||||
|
||||
Copyright (C) 2012 Fredrik Johansson
|
||||
Copyright (C) 2012, 2016 Fredrik Johansson
|
||||
|
||||
******************************************************************************/
|
||||
|
||||
|
@ -28,15 +28,90 @@
|
|||
int
|
||||
arb_get_unique_fmpz(fmpz_t z, const arb_t x)
|
||||
{
|
||||
fmprb_t t;
|
||||
int ans;
|
||||
if (!arb_is_finite(x))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else if (arb_is_exact(x))
|
||||
{
|
||||
/* x = b*2^e, e >= 0 */
|
||||
if (arf_is_int(arb_midref(x)))
|
||||
{
|
||||
/* arf_get_fmpz aborts on overflow */
|
||||
arf_get_fmpz(z, arb_midref(x), ARF_RND_DOWN);
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
/* if the radius is >= 1, there are at least two integers */
|
||||
else if (mag_cmp_2exp_si(arb_radref(x), 0) >= 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
/* there are 0 or 1 integers if the radius is < 1 */
|
||||
else
|
||||
{
|
||||
fmpz_t a, b, exp;
|
||||
int res;
|
||||
|
||||
fmprb_init(t);
|
||||
arb_get_fmprb(t, x);
|
||||
/* if the midpoint is exactly an integer, it is what we want */
|
||||
if (arf_is_int(arb_midref(x)))
|
||||
{
|
||||
/* arf_get_fmpz aborts on overflow */
|
||||
arf_get_fmpz(z, arb_midref(x), ARF_RND_DOWN);
|
||||
return 1;
|
||||
}
|
||||
|
||||
ans = fmprb_get_unique_fmpz(z, t);
|
||||
fmpz_init(a);
|
||||
fmpz_init(b);
|
||||
fmpz_init(exp);
|
||||
|
||||
fmprb_clear(t);
|
||||
return ans;
|
||||
/* if the radius is tiny, it can't be an integer */
|
||||
arf_bot(a, arb_midref(x));
|
||||
|
||||
if (fmpz_cmp(a, MAG_EXPREF(arb_radref(x))) > 0)
|
||||
{
|
||||
res = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
arb_get_interval_fmpz_2exp(a, b, exp, x);
|
||||
|
||||
if (COEFF_IS_MPZ(*exp))
|
||||
{
|
||||
flint_printf("arb_get_unique_fmpz: input too large\n");
|
||||
abort();
|
||||
}
|
||||
|
||||
if (*exp >= 0)
|
||||
{
|
||||
res = fmpz_equal(a, b);
|
||||
|
||||
if (res)
|
||||
{
|
||||
fmpz_mul_2exp(a, a, *exp);
|
||||
fmpz_mul_2exp(b, b, *exp);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
fmpz_cdiv_q_2exp(a, a, -(*exp));
|
||||
fmpz_fdiv_q_2exp(b, b, -(*exp));
|
||||
res = fmpz_equal(a, b);
|
||||
}
|
||||
|
||||
if (res)
|
||||
fmpz_set(z, a);
|
||||
}
|
||||
|
||||
fmpz_clear(a);
|
||||
fmpz_clear(b);
|
||||
fmpz_clear(exp);
|
||||
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -53,7 +53,7 @@ int main()
|
|||
arf_set_fmpz_2exp(y, a, exp);
|
||||
if (!arb_contains_arf(x, y))
|
||||
{
|
||||
flint_printf("FAIL:\n\n");
|
||||
flint_printf("FAIL (a):\n\n");
|
||||
flint_printf("x = "); arb_print(x); flint_printf("\n\n");
|
||||
flint_printf("a = "); fmpz_print(a);
|
||||
flint_printf(" exp = "); fmpz_print(exp); flint_printf("\n\n");
|
||||
|
@ -63,13 +63,24 @@ int main()
|
|||
arf_set_fmpz_2exp(y, b, exp);
|
||||
if (!arb_contains_arf(x, y))
|
||||
{
|
||||
flint_printf("FAIL:\n\n");
|
||||
flint_printf("FAIL (b):\n\n");
|
||||
flint_printf("x = "); arb_print(x); flint_printf("\n\n");
|
||||
flint_printf("b = "); fmpz_print(b);
|
||||
flint_printf(" exp = "); fmpz_print(exp); flint_printf("\n\n");
|
||||
abort();
|
||||
}
|
||||
|
||||
if (fmpz_is_even(a) && fmpz_is_even(b) &&
|
||||
!(fmpz_is_zero(a) && fmpz_is_zero(b)))
|
||||
{
|
||||
flint_printf("FAIL (odd):\n\n");
|
||||
flint_printf("x = "); arb_print(x); flint_printf("\n\n");
|
||||
flint_printf("a = "); fmpz_print(a); flint_printf("\n\n");
|
||||
flint_printf("b = "); fmpz_print(b); flint_printf("\n\n");
|
||||
flint_printf(" exp = "); fmpz_print(exp); flint_printf("\n\n");
|
||||
abort();
|
||||
}
|
||||
|
||||
arb_clear(x);
|
||||
arf_clear(y);
|
||||
fmpz_clear(a);
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
=============================================================================*/
|
||||
/******************************************************************************
|
||||
|
||||
Copyright (C) 2012 Fredrik Johansson
|
||||
Copyright (C) 2012, 2016 Fredrik Johansson
|
||||
|
||||
******************************************************************************/
|
||||
|
||||
|
@ -49,63 +49,103 @@ int main()
|
|||
|
||||
arb_randtest(x, state, 2000, 10);
|
||||
|
||||
unique = arb_get_unique_fmpz(y, x);
|
||||
|
||||
arb_get_interval_fmpz_2exp(a, b, exp, x);
|
||||
if (fmpz_sgn(exp) >= 0)
|
||||
/* generate tiny and huge radii */
|
||||
if (iter % 2 == 0)
|
||||
{
|
||||
fmpz_mul_2exp(a, a, fmpz_get_si(exp));
|
||||
fmpz_mul_2exp(b, b, fmpz_get_si(exp));
|
||||
mag_randtest_special(arb_radref(x), state, 100);
|
||||
|
||||
unique = arb_get_unique_fmpz(y, x);
|
||||
|
||||
arf_get_fmpz(a, arb_midref(x), ARF_RND_FLOOR);
|
||||
fmpz_add_ui(b, a, 1);
|
||||
|
||||
if (unique)
|
||||
{
|
||||
if (arb_contains_fmpz(x, a) == arb_contains_fmpz(x, b))
|
||||
{
|
||||
flint_printf("FAIL (1):\n\n");
|
||||
flint_printf("x = "); arb_printd(x, 100); flint_printf("\n\n");
|
||||
flint_printf("unique = %d\n\n", unique);
|
||||
flint_printf("y = "); fmpz_print(y); flint_printf("\n\n");
|
||||
flint_printf("a = "); fmpz_print(a); flint_printf("\n\n");
|
||||
flint_printf("b = "); fmpz_print(b); flint_printf("\n\n");
|
||||
abort();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (arb_contains_fmpz(x, a) != arb_contains_fmpz(x, b))
|
||||
{
|
||||
flint_printf("FAIL (2):\n\n");
|
||||
flint_printf("x = "); arb_print(x); flint_printf("\n\n");
|
||||
flint_printf("unique = %d\n\n", unique);
|
||||
flint_printf("y = "); fmpz_print(y); flint_printf("\n\n");
|
||||
flint_printf("a = "); fmpz_print(a); flint_printf("\n\n");
|
||||
flint_printf("b = "); fmpz_print(b); flint_printf("\n\n");
|
||||
abort();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
fmpz_cdiv_q_2exp(a, a, -fmpz_get_si(exp));
|
||||
fmpz_fdiv_q_2exp(b, b, -fmpz_get_si(exp));
|
||||
}
|
||||
unique2 = fmpz_equal(a, b);
|
||||
unique = arb_get_unique_fmpz(y, x);
|
||||
|
||||
if ((unique != unique2) || (unique && !fmpz_equal(y, a)))
|
||||
{
|
||||
flint_printf("FAIL:\n\n");
|
||||
flint_printf("x = "); arb_print(x); flint_printf("\n\n");
|
||||
flint_printf("unique = %d, unique2 = %d\n\n", unique, unique2);
|
||||
flint_printf("y = "); fmpz_print(y); flint_printf("\n\n");
|
||||
flint_printf("a = "); fmpz_print(a); flint_printf("\n\n");
|
||||
flint_printf("b = "); fmpz_print(b); flint_printf("\n\n");
|
||||
flint_printf(" exp = "); fmpz_print(exp); flint_printf("\n\n");
|
||||
abort();
|
||||
}
|
||||
|
||||
if (unique)
|
||||
{
|
||||
arb_set_fmpz(z, y);
|
||||
arb_set_round(z, z, 2 + n_randint(state, 1000));
|
||||
|
||||
if (!arb_overlaps(x, z))
|
||||
arb_get_interval_fmpz_2exp(a, b, exp, x);
|
||||
if (fmpz_sgn(exp) >= 0)
|
||||
{
|
||||
flint_printf("FAIL (overlap):\n\n");
|
||||
fmpz_mul_2exp(a, a, fmpz_get_si(exp));
|
||||
fmpz_mul_2exp(b, b, fmpz_get_si(exp));
|
||||
}
|
||||
else
|
||||
{
|
||||
fmpz_cdiv_q_2exp(a, a, -fmpz_get_si(exp));
|
||||
fmpz_fdiv_q_2exp(b, b, -fmpz_get_si(exp));
|
||||
}
|
||||
unique2 = fmpz_equal(a, b);
|
||||
|
||||
if ((unique != unique2) || (unique && !fmpz_equal(y, a)))
|
||||
{
|
||||
flint_printf("FAIL:\n\n");
|
||||
flint_printf("x = "); arb_print(x); flint_printf("\n\n");
|
||||
flint_printf("unique = %d, unique2 = %d\n\n", unique, unique2);
|
||||
flint_printf("y = "); fmpz_print(y); flint_printf("\n\n");
|
||||
flint_printf("z = "); arb_print(z); flint_printf("\n\n");
|
||||
flint_printf("a = "); fmpz_print(a); flint_printf("\n\n");
|
||||
flint_printf("b = "); fmpz_print(b); flint_printf("\n\n");
|
||||
flint_printf(" exp = "); fmpz_print(exp); flint_printf("\n\n");
|
||||
abort();
|
||||
}
|
||||
|
||||
fmpz_add_ui(b, y, 1);
|
||||
if (arb_contains_fmpz(x, b))
|
||||
if (unique)
|
||||
{
|
||||
flint_printf("FAIL (contains a + 1):\n\n");
|
||||
flint_printf("x = "); arb_print(x); flint_printf("\n\n");
|
||||
flint_printf("y = "); fmpz_print(y); flint_printf("\n\n");
|
||||
abort();
|
||||
}
|
||||
arb_set_fmpz(z, y);
|
||||
arb_set_round(z, z, 2 + n_randint(state, 1000));
|
||||
|
||||
fmpz_sub_ui(b, y, 1);
|
||||
if (arb_contains_fmpz(x, b))
|
||||
{
|
||||
flint_printf("FAIL (contains a - 1):\n\n");
|
||||
flint_printf("x = "); arb_print(x); flint_printf("\n\n");
|
||||
flint_printf("y = "); fmpz_print(y); flint_printf("\n\n");
|
||||
abort();
|
||||
if (!arb_overlaps(x, z))
|
||||
{
|
||||
flint_printf("FAIL (overlap):\n\n");
|
||||
flint_printf("x = "); arb_print(x); flint_printf("\n\n");
|
||||
flint_printf("y = "); fmpz_print(y); flint_printf("\n\n");
|
||||
flint_printf("z = "); arb_print(z); flint_printf("\n\n");
|
||||
abort();
|
||||
}
|
||||
|
||||
fmpz_add_ui(b, y, 1);
|
||||
if (arb_contains_fmpz(x, b))
|
||||
{
|
||||
flint_printf("FAIL (contains a + 1):\n\n");
|
||||
flint_printf("x = "); arb_print(x); flint_printf("\n\n");
|
||||
flint_printf("y = "); fmpz_print(y); flint_printf("\n\n");
|
||||
abort();
|
||||
}
|
||||
|
||||
fmpz_sub_ui(b, y, 1);
|
||||
if (arb_contains_fmpz(x, b))
|
||||
{
|
||||
flint_printf("FAIL (contains a - 1):\n\n");
|
||||
flint_printf("x = "); arb_print(x); flint_printf("\n\n");
|
||||
flint_printf("y = "); fmpz_print(y); flint_printf("\n\n");
|
||||
abort();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -368,10 +368,19 @@ Radius and interval operations
|
|||
|
||||
Computes the exact interval represented by *x*, in the form of an integer
|
||||
interval multiplied by a power of two, i.e. `x = [a, b] \times 2^{\text{exp}}`.
|
||||
The result is normalized by removing common trailing zeros
|
||||
from *a* and *b*.
|
||||
|
||||
The outcome is undefined if the midpoint or radius of *x* is non-finite,
|
||||
or if the difference in magnitude between the midpoint and radius
|
||||
is so large that representing the endpoints exactly would cause overflows.
|
||||
This method aborts if *x* is infinite or NaN, or if the difference between
|
||||
the exponents of the midpoint and the radius is so large that allocating
|
||||
memory for the result fails.
|
||||
|
||||
Warning: this method will allocate a huge amount of memory to store
|
||||
the result if the exponent difference is huge. Memory allocation could
|
||||
succeed even if the required space is far larger than the physical
|
||||
memory available on the machine, resulting in swapping. It is recommended
|
||||
to check that the midpoint and radius of *x* both are within a
|
||||
reasonable range before calling this method.
|
||||
|
||||
.. function:: void arb_set_interval_arf(arb_t x, const arf_t a, const arf_t b, slong prec)
|
||||
|
||||
|
@ -420,6 +429,16 @@ Radius and interval operations
|
|||
nonzero. Otherwise (if *x* represents no integers or more than one integer),
|
||||
returns zero.
|
||||
|
||||
This method aborts if there is a unique integer but that integer
|
||||
is so large that allocating memory for the result fails.
|
||||
|
||||
Warning: this method will allocate a huge amount of memory to store
|
||||
the result if there is a unique integer and that integer is huge.
|
||||
Memory allocation could succeed even if the required space is far
|
||||
larger than the physical memory available on the machine, resulting
|
||||
in swapping. It is recommended to check that the midpoint of *x* is
|
||||
within a reasonable range before calling this method.
|
||||
|
||||
.. function:: void arb_floor(arb_t y, const arb_t x, slong prec)
|
||||
|
||||
.. function:: void arb_ceil(arb_t y, const arb_t x, slong prec)
|
||||
|
|
|
@ -258,8 +258,16 @@ Assignment, rounding and conversions
|
|||
|
||||
Sets *z* to *x* rounded to the nearest integer in the direction
|
||||
specified by *rnd*. If rnd is *ARF_RND_NEAR*, rounds to the nearest
|
||||
even integer in case of a tie. Aborts if *x* is infinite, NaN or if the
|
||||
exponent is unreasonably large.
|
||||
even integer in case of a tie.
|
||||
|
||||
This method aborts if *x* is infinite or NaN, or if the exponent of *x*
|
||||
is so large that allocating memory for the result fails.
|
||||
|
||||
Warning: this method will allocate a huge amount of memory to store
|
||||
the result if the exponent of *x* is huge. Memory allocation could
|
||||
succeed even if the required space is far larger than the physical
|
||||
memory available on the machine, resulting in swapping. It is recommended
|
||||
to check that *x* is within a reasonable range before calling this method.
|
||||
|
||||
.. function:: slong arf_get_si(const arf_t x, arf_rnd_t rnd)
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue