numeric.c (flo_to_i): use bigint if the value is bigger than `mrb_int`.
MODIFY
include/mruby/internal.h
include/mruby/internal.h
@@ -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);

MODIFY
src/bigint.c
src/bigint.c
@@ -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)
{

MODIFY
src/numeric.c
src/numeric.c
@@ -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);

numeric.c (flo_to_i): use bigint if the value is bigger than `mrb_int`.