From dee661913f2213bb90bbf541532b326872b049cb Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 16 Apr 2025 22:37:06 +0900 Subject: [PATCH] mruby-numeric-ext (int_sqrt): Integer.sqrt implemented This is the first version. It should support bigint eventually. --- mrbgems/mruby-numeric-ext/src/numeric_ext.c | 32 +++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/mrbgems/mruby-numeric-ext/src/numeric_ext.c b/mrbgems/mruby-numeric-ext/src/numeric_ext.c index 180780eda..ca1067c7b 100644 --- a/mrbgems/mruby-numeric-ext/src/numeric_ext.c +++ b/mrbgems/mruby-numeric-ext/src/numeric_ext.c @@ -262,6 +262,37 @@ flo_remainder(mrb_state *mrb, mrb_value self) } #endif +static mrb_int +isqrt(mrb_int n) +{ + mrb_assert(n >= 0); + if (n < 2) return n; + + mrb_int x = n; + mrb_int y = (x + 1) / 2; + + // Babylonian method (integer version) + while (y < x) { + x = y; + y = (x + n / x) / 2; + } + + return x; +} + +static mrb_value +int_sqrt(mrb_state *mrb, mrb_value self) +{ + mrb_int n; + mrb_get_args(mrb, "i", &n); + if (n < 0) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "non-negative integer required"); + } + + mrb_int result = isqrt(n); + return mrb_int_value(mrb, result); +} + void mrb_mruby_numeric_ext_gem_init(mrb_state* mrb) { @@ -275,6 +306,7 @@ mrb_mruby_numeric_ext_gem_init(mrb_state* mrb) mrb_define_method_id(mrb, ic, MRB_SYM(size), int_size, MRB_ARGS_NONE()); mrb_define_method_id(mrb, ic, MRB_SYM_Q(odd), int_odd, MRB_ARGS_NONE()); mrb_define_method_id(mrb, ic, MRB_SYM_Q(even), int_even, MRB_ARGS_NONE()); + mrb_define_class_method_id(mrb, ic, MRB_SYM(sqrt), int_sqrt, MRB_ARGS_REQ(1)); #ifndef MRB_NO_FLOAT struct RClass *fc = mrb->float_class;