void arb_div_2expm1_ui(arb_t y, const arb_t x, ulong n, long prec) { if (n < FLINT_BITS) { arb_div_ui(y, x, (1UL << n) - 1, prec); } else if (n < 1024 + prec / 32 || n > LONG_MAX / 4) { arb_t t; fmpz_t e; arb_init(t); fmpz_init_set_ui(e, n); arb_one(t); arb_mul_2exp_fmpz(t, t, e); arb_sub_ui(t, t, 1, prec); arb_div(y, x, t, prec); arb_clear(t); fmpz_clear(e); } else { arb_t s, t; long i, b; arb_init(s); arb_init(t); /* x / (2^n - 1) = sum_{k>=1} x * 2^(-k*n)*/ arb_mul_2exp_si(s, x, -n); arb_set(t, s); b = 1; for (i = 2; i <= prec / n + 1; i++) { arb_mul_2exp_si(t, t, -n); arb_add(s, s, t, prec); b = i; } /* error bound: sum_{k>b} x * 2^(-k*n) <= x * 2^(-b*n - (n-1)) */ arb_mul_2exp_si(t, x, -b*n - (n-1)); arb_abs(t, t); arb_add_error(s, t); arb_set(y, s); arb_clear(s); arb_clear(t); } }
void _arb_poly_mullow_block(arb_ptr z, arb_srcptr x, slong xlen, arb_srcptr y, slong ylen, slong n, slong prec) { slong xmlen, xrlen, ymlen, yrlen, i; fmpz *xz, *yz, *zz; fmpz *xe, *ye; slong *xblocks, *yblocks; int squaring; fmpz_t scale, t; xlen = FLINT_MIN(xlen, n); ylen = FLINT_MIN(ylen, n); squaring = (x == y) && (xlen == ylen); /* Strip trailing zeros */ xmlen = xrlen = xlen; while (xmlen > 0 && arf_is_zero(arb_midref(x + xmlen - 1))) xmlen--; while (xrlen > 0 && mag_is_zero(arb_radref(x + xrlen - 1))) xrlen--; if (squaring) { ymlen = xmlen; yrlen = xrlen; } else { ymlen = yrlen = ylen; while (ymlen > 0 && arf_is_zero(arb_midref(y + ymlen - 1))) ymlen--; while (yrlen > 0 && mag_is_zero(arb_radref(y + yrlen - 1))) yrlen--; } /* We don't know how to deal with infinities or NaNs */ if (!_arb_vec_is_finite(x, xlen) || (!squaring && !_arb_vec_is_finite(y, ylen))) { _arb_poly_mullow_classical(z, x, xlen, y, ylen, n, prec); return; } xlen = FLINT_MAX(xmlen, xrlen); ylen = FLINT_MAX(ymlen, yrlen); /* Start with the zero polynomial */ _arb_vec_zero(z, n); /* Nothing to do */ if (xlen == 0 || ylen == 0) return; n = FLINT_MIN(n, xlen + ylen - 1); fmpz_init(scale); fmpz_init(t); xz = _fmpz_vec_init(xlen); yz = _fmpz_vec_init(ylen); zz = _fmpz_vec_init(n); xe = _fmpz_vec_init(xlen); ye = _fmpz_vec_init(ylen); xblocks = flint_malloc(sizeof(slong) * (xlen + 1)); yblocks = flint_malloc(sizeof(slong) * (ylen + 1)); _arb_poly_get_scale(scale, x, xlen, y, ylen); /* Error propagation */ /* (xm + xr)*(ym + yr) = (xm*ym) + (xr*ym + xm*yr + xr*yr) = (xm*ym) + (xm*yr + xr*(ym + yr)) */ if (xrlen != 0 || yrlen != 0) { mag_ptr tmp; double *xdbl, *ydbl; tmp = _mag_vec_init(FLINT_MAX(xlen, ylen)); xdbl = flint_malloc(sizeof(double) * xlen); ydbl = flint_malloc(sizeof(double) * ylen); /* (xm + xr)^2 = (xm*ym) + (xr^2 + 2 xm xr) = (xm*ym) + xr*(2 xm + xr) */ if (squaring) { _mag_vec_get_fmpz_2exp_blocks(xz, xdbl, xe, xblocks, scale, x, NULL, xrlen); for (i = 0; i < xlen; i++) { arf_get_mag(tmp + i, arb_midref(x + i)); mag_mul_2exp_si(tmp + i, tmp + i, 1); mag_add(tmp + i, tmp + i, arb_radref(x + i)); } _mag_vec_get_fmpz_2exp_blocks(yz, ydbl, ye, yblocks, scale, NULL, tmp, xlen); _arb_poly_addmullow_rad(z, zz, xz, xdbl, xe, xblocks, xrlen, yz, ydbl, ye, yblocks, xlen, n); } else if (yrlen == 0) { /* xr * |ym| */ _mag_vec_get_fmpz_2exp_blocks(xz, xdbl, xe, xblocks, scale, x, NULL, xrlen); for (i = 0; i < ymlen; i++) arf_get_mag(tmp + i, arb_midref(y + i)); _mag_vec_get_fmpz_2exp_blocks(yz, ydbl, ye, yblocks, scale, NULL, tmp, ymlen); _arb_poly_addmullow_rad(z, zz, xz, xdbl, xe, xblocks, xrlen, yz, ydbl, ye, yblocks, ymlen, n); } else { /* |xm| * yr */ for (i = 0; i < xmlen; i++) arf_get_mag(tmp + i, arb_midref(x + i)); _mag_vec_get_fmpz_2exp_blocks(xz, xdbl, xe, xblocks, scale, NULL, tmp, xmlen); _mag_vec_get_fmpz_2exp_blocks(yz, ydbl, ye, yblocks, scale, y, NULL, yrlen); _arb_poly_addmullow_rad(z, zz, xz, xdbl, xe, xblocks, xmlen, yz, ydbl, ye, yblocks, yrlen, n); /* xr*(|ym| + yr) */ if (xrlen != 0) { _mag_vec_get_fmpz_2exp_blocks(xz, xdbl, xe, xblocks, scale, x, NULL, xrlen); for (i = 0; i < ylen; i++) arb_get_mag(tmp + i, y + i); _mag_vec_get_fmpz_2exp_blocks(yz, ydbl, ye, yblocks, scale, NULL, tmp, ylen); _arb_poly_addmullow_rad(z, zz, xz, xdbl, xe, xblocks, xrlen, yz, ydbl, ye, yblocks, ylen, n); } } _mag_vec_clear(tmp, FLINT_MAX(xlen, ylen)); flint_free(xdbl); flint_free(ydbl); } /* multiply midpoints */ if (xmlen != 0 && ymlen != 0) { _arb_vec_get_fmpz_2exp_blocks(xz, xe, xblocks, scale, x, xmlen, prec); if (squaring) { _arb_poly_addmullow_block(z, zz, xz, xe, xblocks, xmlen, xz, xe, xblocks, xmlen, n, prec, 1); } else { _arb_vec_get_fmpz_2exp_blocks(yz, ye, yblocks, scale, y, ymlen, prec); _arb_poly_addmullow_block(z, zz, xz, xe, xblocks, xmlen, yz, ye, yblocks, ymlen, n, prec, 0); } } /* Unscale. */ if (!fmpz_is_zero(scale)) { fmpz_zero(t); for (i = 0; i < n; i++) { arb_mul_2exp_fmpz(z + i, z + i, t); fmpz_add(t, t, scale); } } _fmpz_vec_clear(xz, xlen); _fmpz_vec_clear(yz, ylen); _fmpz_vec_clear(zz, n); _fmpz_vec_clear(xe, xlen); _fmpz_vec_clear(ye, ylen); flint_free(xblocks); flint_free(yblocks); fmpz_clear(scale); fmpz_clear(t); }