void mag_sqrt(mag_t y, const mag_t x) { if (mag_is_special(x)) { mag_set(y, x); } else { double t; fmpz e; t = MAG_MAN(x) * ldexp(1.0, -MAG_BITS); e = MAG_EXP(x); if (!COEFF_IS_MPZ(e)) { if (e % 2 != 0) { e = (e - 1) >> 1; t *= 2.0; } else { e >>= 1; } t = sqrt(t) * (1 + 1e-13); mag_set_d_2exp_fmpz(y, t, &e); }
void mag_rfac_ui(mag_t z, ulong n) { if (n < MAG_FAC_TABLE_NUM) { _fmpz_demote(MAG_EXPREF(z)); MAG_EXP(z) = mag_rfac_tab[n * 2]; MAG_MAN(z) = mag_rfac_tab[n * 2 + 1]; } else { double x = n; x = ceil((((x+0.5)*mag_d_log_lower_bound(x) - x) * 1.4426950408889634074) * -0.9999999); /* x + 1 could round down for huge x, but this doesn't matter as long as the value was perturbed up above */ fmpz_set_d(MAG_EXPREF(z), x + 1); MAG_MAN(z) = MAG_ONE_HALF; } }
void mag_expinv(mag_t res, const mag_t x) { if (mag_is_zero(x)) { mag_one(res); } else if (mag_is_inf(x)) { mag_zero(res); } else if (fmpz_sgn(MAG_EXPREF(x)) <= 0) { mag_one(res); } else if (fmpz_cmp_ui(MAG_EXPREF(x), 2 * MAG_BITS) > 0) { fmpz_t t; fmpz_init(t); /* If x > 2^60, exp(-x) < 2^(-2^60 / log(2)) */ /* -1/log(2) < -369/256 */ fmpz_set_si(t, -369); fmpz_mul_2exp(t, t, 2 * MAG_BITS - 8); mag_one(res); mag_mul_2exp_fmpz(res, res, t); fmpz_clear(t); } else { fmpz_t t; slong e = MAG_EXP(x); fmpz_init(t); fmpz_set_ui(t, MAG_MAN(x)); if (e >= MAG_BITS) fmpz_mul_2exp(t, t, e - MAG_BITS); else fmpz_tdiv_q_2exp(t, t, MAG_BITS - e); /* upper bound for 1/e */ mag_set_ui_2exp_si(res, 395007543, -30); mag_pow_fmpz(res, res, t); fmpz_clear(t); } }
void mag_set_d_lower(mag_t z, double c) { if (c < 0.0) c = -c; if (c == 0.0 || (c != c)) { mag_zero(z); } else if (c == D_INF) { mag_inf(z); } else { _fmpz_demote(MAG_EXPREF(z)); MAG_SET_D_2EXP_LOWER(MAG_MAN(z), MAG_EXP(z), c, 0); } }
void arb_const_log2(arb_t res, slong prec) { if (prec < ARB_LOG_TAB2_LIMBS * FLINT_BITS - 16) { slong exp; /* just reading the table is known to give the correct rounding */ _arf_set_round_mpn(arb_midref(res), &exp, arb_log_log2_tab, ARB_LOG_TAB2_LIMBS, 0, prec, ARF_RND_NEAR); _fmpz_set_si_small(ARF_EXPREF(arb_midref(res)), exp); /* 1/2 ulp error */ _fmpz_set_si_small(MAG_EXPREF(arb_radref(res)), exp - prec); MAG_MAN(arb_radref(res)) = MAG_ONE_HALF; } else { arb_const_log2_hypgeom(res, prec); } }
double mag_get_d(const mag_t z) { if (mag_is_zero(z)) { return 0.0; } else if (mag_is_inf(z)) { return D_INF; } else if (MAG_EXP(z) < -1000 || MAG_EXP(z) > 1000) { if (fmpz_sgn(MAG_EXPREF(z)) < 0) return ldexp(1.0, -1000); else return D_INF; } else { return ldexp(MAG_MAN(z), MAG_EXP(z) - MAG_BITS); } }
static __inline__ void _mag_vec_get_fmpz_2exp_blocks(fmpz * coeffs, double * dblcoeffs, fmpz * exps, slong * blocks, const fmpz_t scale, arb_srcptr x, mag_srcptr xm, slong len) { fmpz_t top, bot, t, b, v, block_top, block_bot; slong i, j, s, block, bits, maxheight; int in_zero; mag_srcptr cur; fmpz_init(top); fmpz_init(bot); fmpz_init(t); fmpz_init(b); fmpz_init(v); fmpz_init(block_top); fmpz_init(block_bot); blocks[0] = 0; block = 0; in_zero = 1; maxheight = ALPHA * MAG_BITS + BETA; if (maxheight > DOUBLE_BLOCK_MAX_HEIGHT) abort(); for (i = 0; i < len; i++) { cur = (x == NULL) ? (xm + i) : arb_radref(x + i); /* Skip (must be zero, since we assume there are no Infs/NaNs). */ if (mag_is_special(cur)) continue; /* Bottom and top exponent of current number */ bits = MAG_BITS; fmpz_set(top, MAG_EXPREF(cur)); fmpz_submul_ui(top, scale, i); fmpz_sub_ui(bot, top, bits); /* Extend current block. */ if (in_zero) { fmpz_swap(block_top, top); fmpz_swap(block_bot, bot); } else { fmpz_max(t, top, block_top); fmpz_min(b, bot, block_bot); fmpz_sub(v, t, b); /* extend current block */ if (fmpz_cmp_ui(v, maxheight) < 0) { fmpz_swap(block_top, t); fmpz_swap(block_bot, b); } else /* start new block */ { /* write exponent for previous block */ fmpz_set(exps + block, block_bot); block++; blocks[block] = i; fmpz_swap(block_top, top); fmpz_swap(block_bot, bot); } } in_zero = 0; } /* write exponent for last block */ fmpz_set(exps + block, block_bot); /* end marker */ blocks[block + 1] = len; /* write the block data */ for (i = 0; blocks[i] != len; i++) { for (j = blocks[i]; j < blocks[i + 1]; j++) { cur = (x == NULL) ? (xm + j) : arb_radref(x + j); if (mag_is_special(cur)) { fmpz_zero(coeffs + j); dblcoeffs[j] = 0.0; } else { mp_limb_t man; double c; man = MAG_MAN(cur); /* TODO: only write and use doubles when block is short? */ /* Divide by 2^(scale * j) */ fmpz_mul_ui(t, scale, j); fmpz_sub(t, MAG_EXPREF(cur), t); fmpz_sub_ui(t, t, MAG_BITS); /* bottom exponent */ s = _fmpz_sub_small(t, exps + i); if (s < 0) abort(); /* Bug catcher */ fmpz_set_ui(coeffs + j, man); fmpz_mul_2exp(coeffs + j, coeffs + j, s); c = man; c = ldexp(c, s - DOUBLE_BLOCK_SHIFT); if (c < 1e-150 || c > 1e150) /* Bug catcher */ abort(); dblcoeffs[j] = c; } } } fmpz_clear(top); fmpz_clear(bot); fmpz_clear(t); fmpz_clear(b); fmpz_clear(v); fmpz_clear(block_top); fmpz_clear(block_bot); }
void mag_log1p(mag_t z, const mag_t x) { if (mag_is_special(x)) { if (mag_is_zero(x)) mag_zero(z); else mag_inf(z); } else { fmpz exp = MAG_EXP(x); if (!COEFF_IS_MPZ(exp)) { /* Quick bound by x */ if (exp < -10) { mag_set(z, x); return; } else if (exp < 1000) { double t; t = ldexp(MAG_MAN(x), exp - MAG_BITS); t = (1.0 + t) * (1 + 1e-14); t = mag_d_log_upper_bound(t); mag_set_d(z, t); return; } } else if (fmpz_sgn(MAG_EXPREF(x)) < 0) { /* Quick bound by x */ mag_set(z, x); return; } /* Now we must have x >= 2^1000 */ /* Use log(2^(exp-1) * (2*v)) = exp*log(2) + log(2*v) */ { double t; fmpz_t b; mag_t u; mag_init(u); fmpz_init(b); /* incrementing the mantissa gives an upper bound for x+1 */ t = ldexp(MAG_MAN(x) + 1, 1 - MAG_BITS); t = mag_d_log_upper_bound(t); mag_set_d(u, t); /* log(2) < 744261118/2^30 */ _fmpz_add_fast(b, MAG_EXPREF(x), -1); fmpz_mul_ui(b, b, 744261118); mag_set_fmpz(z, b); _fmpz_add_fast(MAG_EXPREF(z), MAG_EXPREF(z), -30); mag_add(z, z, u); mag_clear(u); fmpz_clear(b); } } }