in GaiaXAndroidQuickJS/quickjs/gxquickjs/libbf.c [6949:7052]
int bfdec_divrem(bfdec_t *q, bfdec_t *r, const bfdec_t *a, const bfdec_t *b,
limb_t prec, bf_flags_t flags, int rnd_mode)
{
bf_context_t *s = q->ctx;
bfdec_t a1_s, *a1 = &a1_s;
bfdec_t b1_s, *b1 = &b1_s;
bfdec_t r1_s, *r1 = &r1_s;
int q_sign, res;
BOOL is_ceil, is_rndn;
assert(q != a && q != b);
assert(r != a && r != b);
assert(q != r);
if (a->len == 0 || b->len == 0) {
bfdec_set_zero(q, 0);
if (a->expn == BF_EXP_NAN || b->expn == BF_EXP_NAN) {
bfdec_set_nan(r);
return 0;
} else if (a->expn == BF_EXP_INF || b->expn == BF_EXP_ZERO) {
bfdec_set_nan(r);
return BF_ST_INVALID_OP;
} else {
bfdec_set(r, a);
return bfdec_round(r, prec, flags);
}
}
q_sign = a->sign ^ b->sign;
is_rndn = (rnd_mode == BF_RNDN || rnd_mode == BF_RNDNA);
switch(rnd_mode) {
default:
case BF_RNDZ:
case BF_RNDN:
case BF_RNDNA:
is_ceil = FALSE;
break;
case BF_RNDD:
is_ceil = q_sign;
break;
case BF_RNDU:
is_ceil = q_sign ^ 1;
break;
case BF_RNDA:
is_ceil = TRUE;
break;
case BF_DIVREM_EUCLIDIAN:
is_ceil = a->sign;
break;
}
a1->expn = a->expn;
a1->tab = a->tab;
a1->len = a->len;
a1->sign = 0;
b1->expn = b->expn;
b1->tab = b->tab;
b1->len = b->len;
b1->sign = 0;
// bfdec_print_str("a1", a1);
// bfdec_print_str("b1", b1);
/* XXX: could improve to avoid having a large 'q' */
bfdec_tdivremu(s, q, r, a1, b1);
if (bfdec_is_nan(q) || bfdec_is_nan(r))
goto fail;
// bfdec_print_str("q", q);
// bfdec_print_str("r", r);
if (r->len != 0) {
if (is_rndn) {
bfdec_init(s, r1);
if (bfdec_set(r1, r))
goto fail;
if (bfdec_mul_si(r1, r1, 2, BF_PREC_INF, BF_RNDZ)) {
bfdec_delete(r1);
goto fail;
}
res = bfdec_cmpu(r1, b);
bfdec_delete(r1);
if (res > 0 ||
(res == 0 &&
(rnd_mode == BF_RNDNA ||
(get_digit(q->tab, q->len, q->len * LIMB_DIGITS - q->expn) & 1) != 0))) {
goto do_sub_r;
}
} else if (is_ceil) {
do_sub_r:
res = bfdec_add_si(q, q, 1, BF_PREC_INF, BF_RNDZ);
res |= bfdec_sub(r, r, b1, BF_PREC_INF, BF_RNDZ);
if (res & BF_ST_MEM_ERROR)
goto fail;
}
}
r->sign ^= a->sign;
q->sign = q_sign;
return bfdec_round(r, prec, flags);
fail:
bfdec_set_nan(q);
bfdec_set_nan(r);
return BF_ST_MEM_ERROR;
}