mirror of
https://github.com/mruby/mruby
synced 2026-06-08 16:11:16 +00:00
numeric.c (flo_to_i): use bigint if the value is bigger than mrb_int.
This commit is contained in:
@@ -181,6 +181,7 @@ mrb_value mrb_bint_lshift(mrb_state *mrb, mrb_value x, mrb_int width);
|
||||
mrb_value mrb_bint_rshift(mrb_state *mrb, mrb_value x, mrb_int width);
|
||||
mrb_value mrb_bint_to_s(mrb_state *mrb, mrb_value x, mrb_int base);
|
||||
#ifndef MRB_NO_FLOAT
|
||||
mrb_value mrb_bint_new_float(mrb_state *mrb, mrb_float x);
|
||||
mrb_float mrb_bint_as_float(mrb_state *mrb, mrb_value x);
|
||||
#endif
|
||||
mrb_int mrb_bint_as_int(mrb_state *mrb, mrb_value x);
|
||||
|
||||
@@ -1011,6 +1011,54 @@ mrb_gc_free_bint(mrb_state *mrb, struct RBasic *x)
|
||||
}
|
||||
|
||||
#ifndef MRB_NO_FLOAT
|
||||
mrb_value
|
||||
mrb_bint_new_float(mrb_state *mrb, mrb_float x)
|
||||
{
|
||||
/* x should not be NaN nor Infinity */
|
||||
mrb_assert(x == x && x != x * 0.5);
|
||||
|
||||
if (x < 1.0) {
|
||||
return mrb_fixnum_value(0);
|
||||
}
|
||||
|
||||
struct RBigint *bint = bint_new(mrb);
|
||||
mpz_t *r = &bint->mp;
|
||||
|
||||
if (x < 0.0) {
|
||||
x = -x;
|
||||
r->sn = -1;
|
||||
}
|
||||
else {
|
||||
r->sn = 1;
|
||||
}
|
||||
|
||||
mrb_float b = (double)CMASK;
|
||||
mrb_float bi = 1.0 / b;
|
||||
size_t rn;
|
||||
int i;
|
||||
mp_limb *rp;
|
||||
mp_limb f;
|
||||
|
||||
for (rn = 1; x >= b; rn++)
|
||||
x *= bi;
|
||||
|
||||
mpz_realloc(mrb, r, rn);
|
||||
rp = r->p;
|
||||
f = (mp_limb)x;
|
||||
x -= f;
|
||||
mrb_assert(x < 1.0);
|
||||
i = rn-1;
|
||||
rp[i] = f;
|
||||
while (--i >= 0) {
|
||||
x = b * x;
|
||||
f = (mp_limb)x;
|
||||
x -= f;
|
||||
mrb_assert(x < 1.0);
|
||||
rp[i] = f;
|
||||
}
|
||||
return bint_norm(mrb, bint);
|
||||
}
|
||||
|
||||
mrb_float
|
||||
mrb_bint_as_float(mrb_state *mrb, mrb_value self)
|
||||
{
|
||||
|
||||
@@ -1014,7 +1014,11 @@ flo_to_i(mrb_state *mrb, mrb_value num)
|
||||
mrb_check_num_exact(mrb, f);
|
||||
|
||||
if (!FIXABLE_FLOAT(f)) {
|
||||
#ifdef MRB_USE_BIGINT
|
||||
return mrb_bint_new_float(mrb, f);
|
||||
#else
|
||||
mrb_int_overflow(mrb, "to_f");
|
||||
#endif
|
||||
}
|
||||
if (f > 0.0) f = floor(f);
|
||||
if (f < 0.0) f = ceil(f);
|
||||
|
||||
Reference in New Issue
Block a user