JavaScript-QuickJS
view release on metacpan or search on metacpan
quickjs/libbf.c view on Meta::CPAN
slimb_t i;
// bf_print_str("bf_renorm", r);
l = r->len;
while (l > 0 && r->tab[l - 1] == 0)
l--;
if (l == 0) {
/* zero */
r->expn = BF_EXP_ZERO;
bf_resize(r, 0); /* cannot fail */
ret = 0;
} else {
r->expn -= (r->len - l) * LIMB_BITS;
/* shift to have the MSB set to '1' */
v = r->tab[l - 1];
shift = clz(v);
if (shift != 0) {
v = 0;
for(i = 0; i < l; i++) {
a = r->tab[i];
r->tab[i] = (a << shift) | (v >> (LIMB_BITS - shift));
v = a;
}
r->expn -= shift;
}
ret = __bf_round(r, prec1, flags, l, 0);
}
// bf_print_str("r_final", r);
return ret;
}
/* return true if rounding can be done at precision 'prec' assuming
the exact result r is such that |r-a| <= 2^(EXP(a)-k). */
/* XXX: check the case where the exponent would be incremented by the
rounding */
int bf_can_round(const bf_t *a, slimb_t prec, bf_rnd_t rnd_mode, slimb_t k)
{
BOOL is_rndn;
slimb_t bit_pos, n;
limb_t bit;
if (a->expn == BF_EXP_INF || a->expn == BF_EXP_NAN)
return FALSE;
if (rnd_mode == BF_RNDF) {
return (k >= (prec + 1));
}
if (a->expn == BF_EXP_ZERO)
return FALSE;
is_rndn = (rnd_mode == BF_RNDN || rnd_mode == BF_RNDNA);
if (k < (prec + 2))
return FALSE;
bit_pos = a->len * LIMB_BITS - 1 - prec;
n = k - prec;
/* bit pattern for RNDN or RNDNA: 0111.. or 1000...
for other rounding modes: 000... or 111...
*/
bit = get_bit(a->tab, a->len, bit_pos);
bit_pos--;
n--;
bit ^= is_rndn;
/* XXX: slow, but a few iterations on average */
while (n != 0) {
if (get_bit(a->tab, a->len, bit_pos) != bit)
return TRUE;
bit_pos--;
n--;
}
return FALSE;
}
/* Cannot fail with BF_ST_MEM_ERROR. */
int bf_round(bf_t *r, limb_t prec, bf_flags_t flags)
{
if (r->len == 0)
return 0;
return __bf_round(r, prec, flags, r->len, 0);
}
/* for debugging */
static __maybe_unused void dump_limbs(const char *str, const limb_t *tab, limb_t n)
{
limb_t i;
printf("%s: len=%" PRId_LIMB "\n", str, n);
for(i = 0; i < n; i++) {
printf("%" PRId_LIMB ": " FMT_LIMB "\n",
i, tab[i]);
}
}
void mp_print_str(const char *str, const limb_t *tab, limb_t n)
{
slimb_t i;
printf("%s= 0x", str);
for(i = n - 1; i >= 0; i--) {
if (i != (n - 1))
printf("_");
printf(FMT_LIMB, tab[i]);
}
printf("\n");
}
static __maybe_unused void mp_print_str_h(const char *str,
const limb_t *tab, limb_t n,
limb_t high)
{
slimb_t i;
printf("%s= 0x", str);
printf(FMT_LIMB, high);
for(i = n - 1; i >= 0; i--) {
printf("_");
printf(FMT_LIMB, tab[i]);
}
printf("\n");
}
/* for debugging */
void bf_print_str(const char *str, const bf_t *a)
{
slimb_t i;
printf("%s=", str);
quickjs/libbf.c view on Meta::CPAN
int ret;
assert(r != a);
if (a->len == 0) {
if (a->expn == BF_EXP_NAN) {
bf_set_nan(r);
} else if (a->expn == BF_EXP_INF) {
if (a->sign)
bf_set_zero(r, 0);
else
bf_set_inf(r, 0);
} else {
bf_set_ui(r, 1);
}
return 0;
}
ret = check_exp_underflow_overflow(s, r, a, a, prec, flags);
if (ret)
return ret;
if (a->expn < 0 && (-a->expn) >= (prec + 2)) {
/* small argument case: result = 1 + epsilon * sign(x) */
bf_set_ui(r, 1);
return bf_add_epsilon(r, r, -(prec + 2), a->sign, prec, flags);
}
return bf_ziv_rounding(r, a, prec, flags, bf_exp_internal, NULL);
}
static int bf_log_internal(bf_t *r, const bf_t *a, limb_t prec, void *opaque)
{
bf_context_t *s = r->ctx;
bf_t T_s, *T = &T_s;
bf_t U_s, *U = &U_s;
bf_t V_s, *V = &V_s;
slimb_t n, prec1, l, i, K;
assert(r != a);
bf_init(s, T);
/* argument reduction 1 */
/* T=a*2^n with 2/3 <= T <= 4/3 */
{
bf_t U_s, *U = &U_s;
bf_set(T, a);
n = T->expn;
T->expn = 0;
/* U= ~ 2/3 */
bf_init(s, U);
bf_set_ui(U, 0xaaaaaaaa);
U->expn = 0;
if (bf_cmp_lt(T, U)) {
T->expn++;
n--;
}
bf_delete(U);
}
// printf("n=%ld\n", n);
// bf_print_str("T", T);
/* XXX: precision analysis */
/* number of iterations for argument reduction 2 */
K = bf_isqrt((prec + 1) / 2);
/* order of Taylor expansion */
l = prec / (2 * K) + 1;
/* precision of the intermediate computations */
prec1 = prec + K + 2 * l + 32;
bf_init(s, U);
bf_init(s, V);
/* Note: cancellation occurs here, so we use more precision (XXX:
reduce the precision by computing the exact cancellation) */
bf_add_si(T, T, -1, BF_PREC_INF, BF_RNDN);
/* argument reduction 2 */
for(i = 0; i < K; i++) {
/* T = T / (1 + sqrt(1 + T)) */
bf_add_si(U, T, 1, prec1, BF_RNDN);
bf_sqrt(V, U, prec1, BF_RNDF);
bf_add_si(U, V, 1, prec1, BF_RNDN);
bf_div(T, T, U, prec1, BF_RNDN);
}
{
bf_t Y_s, *Y = &Y_s;
bf_t Y2_s, *Y2 = &Y2_s;
bf_init(s, Y);
bf_init(s, Y2);
/* compute ln(1+x) = ln((1+y)/(1-y)) with y=x/(2+x)
= y + y^3/3 + ... + y^(2*l + 1) / (2*l+1)
with Y=Y^2
= y*(1+Y/3+Y^2/5+...) = y*(1+Y*(1/3+Y*(1/5 + ...)))
*/
bf_add_si(Y, T, 2, prec1, BF_RNDN);
bf_div(Y, T, Y, prec1, BF_RNDN);
bf_mul(Y2, Y, Y, prec1, BF_RNDN);
bf_set_ui(r, 0);
for(i = l; i >= 1; i--) {
bf_set_ui(U, 1);
bf_set_ui(V, 2 * i + 1);
bf_div(U, U, V, prec1, BF_RNDN);
bf_add(r, r, U, prec1, BF_RNDN);
bf_mul(r, r, Y2, prec1, BF_RNDN);
}
bf_add_si(r, r, 1, prec1, BF_RNDN);
bf_mul(r, r, Y, prec1, BF_RNDN);
bf_delete(Y);
bf_delete(Y2);
}
bf_delete(V);
bf_delete(U);
/* multiplication by 2 for the Taylor expansion and undo the
argument reduction 2*/
bf_mul_2exp(r, K + 1, BF_PREC_INF, BF_RNDZ);
/* undo the argument reduction 1 */
bf_const_log2(T, prec1, BF_RNDF);
bf_mul_si(T, T, n, prec1, BF_RNDN);
( run in 0.716 second using v1.01-cache-2.11-cpan-71847e10f99 )