mirror of
https://github.com/mruby/mruby
synced 2026-06-08 16:11:16 +00:00
mruby-numeric-ext: add Integer#bit_length
Implement Integer#bit_length in mrbgems/mruby-numeric-ext. - Fixnum: zero returns 0; negatives follow ~self rule; count bits by shifts. - Bigint (MRB_USE_BIGINT): handle sign; negatives via mrb_bint_rev, then bit length via length of mrb_bint_to_s(..., 2). - Add tests in mrbgems/mruby-numeric-ext/test/numeric.rb. - Update README with examples. Co-authored-by: Codex CLI <codex@openai.com>
This commit is contained in:
@@ -21,6 +21,7 @@ This gem adds the following methods:
|
||||
- `allbits?(mask)`: Returns `true` if all bits of `self & mask` are 1.
|
||||
- `anybits?(mask)`: Returns `true` if any bits of `self & mask` are 1.
|
||||
- `nobits?(mask)`: Returns `true` if no bits of `self & mask` are 1.
|
||||
- `bit_length`: Returns the number of bits of the absolute value of `self` in binary. `0.bit_length #=> 0`; `(-1).bit_length #=> 0`; `2.bit_length #=> 2`.
|
||||
- `ceildiv(other)`: Returns the result of `self` divided by `other`, rounded up to the nearest integer.
|
||||
- `integer?`: Returns `true` (overrides `Numeric#integer?`).
|
||||
- `remainder(numeric)`: Returns the remainder of `self` divided by `numeric`. Equivalent to `x - y * (x / y).truncate`.
|
||||
@@ -69,6 +70,7 @@ p 12345.digits # => [5, 4, 3, 2, 1]
|
||||
p 12345.digits(16) # => [9, 3, 0, 3]
|
||||
|
||||
p 42.size # => (depends on machine, e.g., 4 or 8)
|
||||
p 5.bit_length # => 3
|
||||
p 5.odd? # => true
|
||||
p 4.even? # => true
|
||||
p Integer.sqrt(16) # => 4
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include <mruby.h>
|
||||
#include <mruby/numeric.h>
|
||||
#include <mruby/array.h>
|
||||
#include <mruby/string.h>
|
||||
#include <mruby/internal.h>
|
||||
#include <mruby/presym.h>
|
||||
|
||||
@@ -8,6 +9,40 @@
|
||||
static mrb_value flo_remainder(mrb_state *mrb, mrb_value self);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* int.bit_length -> integer
|
||||
*
|
||||
* Returns the number of bits of the absolute value of self in binary representation.
|
||||
* For zero, returns 0. For negative integers, behaves as (~self).bit_length
|
||||
* (e.g., (-1).bit_length => 0, (-2).bit_length => 1).
|
||||
*/
|
||||
static mrb_value
|
||||
int_bit_length(mrb_state *mrb, mrb_value self)
|
||||
{
|
||||
#ifdef MRB_USE_BIGINT
|
||||
if (mrb_bigint_p(self)) {
|
||||
mrb_int sign = mrb_bint_sign(mrb, self);
|
||||
if (sign == 0) return mrb_fixnum_value(0);
|
||||
mrb_value v = self;
|
||||
if (sign < 0) v = mrb_bint_rev(mrb, self); /* ~self = -self-1 */
|
||||
mrb_value s = mrb_bint_to_s(mrb, v, 2);
|
||||
return mrb_int_value(mrb, (mrb_int)RSTRING_LEN(s));
|
||||
}
|
||||
#endif
|
||||
mrb_int x = mrb_integer(self);
|
||||
if (x == 0) return mrb_fixnum_value(0);
|
||||
|
||||
/* for negative fixnums, use ~x */
|
||||
mrb_uint ux = (mrb_uint)(x < 0 ? ~x : x);
|
||||
mrb_int bits = 0;
|
||||
while (ux) {
|
||||
bits++;
|
||||
ux >>= 1;
|
||||
}
|
||||
return mrb_int_value(mrb, bits);
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* num.remainder(numeric) -> real
|
||||
@@ -435,6 +470,7 @@ mrb_mruby_numeric_ext_gem_init(mrb_state* mrb)
|
||||
mrb_define_method_id(mrb, ic, MRB_SYM(pow), int_powm, MRB_ARGS_ARG(1,1));
|
||||
mrb_define_method_id(mrb, ic, MRB_SYM(digits), int_digits, MRB_ARGS_OPT(1));
|
||||
mrb_define_method_id(mrb, ic, MRB_SYM(size), int_size, MRB_ARGS_NONE());
|
||||
mrb_define_method_id(mrb, ic, MRB_SYM(bit_length), int_bit_length, 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_method_id(mrb, ic, MRB_SYM(gcd), int_gcd, MRB_ARGS_REQ(1));
|
||||
|
||||
@@ -111,3 +111,27 @@ assert('Integer.sqrt') do
|
||||
assert_equal(10, Integer.sqrt(100))
|
||||
assert_equal(85, Integer.sqrt(7244))
|
||||
end
|
||||
|
||||
assert('Integer#bit_length') do
|
||||
# zero
|
||||
assert_equal 0, 0.bit_length
|
||||
|
||||
# positives
|
||||
assert_equal 1, 1.bit_length
|
||||
assert_equal 2, 2.bit_length
|
||||
assert_equal 2, 3.bit_length
|
||||
assert_equal 3, 4.bit_length
|
||||
assert_equal 3, 5.bit_length
|
||||
|
||||
# negatives (use ~n semantics)
|
||||
assert_equal 0, (-1).bit_length
|
||||
assert_equal 1, (-2).bit_length
|
||||
assert_equal 2, (-3).bit_length
|
||||
assert_equal 2, (-4).bit_length
|
||||
assert_equal 3, (-5).bit_length
|
||||
|
||||
# bigint cases may be enabled depending on config
|
||||
# assert_equal 100, (2**100 - 1).bit_length
|
||||
# assert_equal 101, (2**100).bit_length
|
||||
# assert_equal 0, (-1).bit_length
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user