mirror of
https://github.com/ruby/ruby.git
synced 2026-10-28 16:36:20 +08:00
[Feature #20163] Add Integer#bit_count
This commit is contained in:
1 parent
0b2b21767b
commit
23c056c83c
6 files changed
+129
Notes:
git
2026-07-10 18:56:35 +00:00
No files matched your search
@@ -7029,6 +7029,23 @@ rb_big_bit_length(VALUE big)
|
||||
INTEGER_PACK_LSWORD_FIRST|INTEGER_PACK_NATIVE_BYTE_ORDER);
|
||||
}
|
||||
|
||||
VALUE
|
||||
rb_big_bit_count(VALUE big)
|
||||
{
|
||||
if (BIGNUM_NEGATIVE_P(big))
|
||||
rb_raise(rb_eArgError, "bit_count is undefined for negative integers");
|
||||
|
||||
BDIGIT *ds = BDIGITS(big);
|
||||
size_t n = BIGNUM_LEN(big);
|
||||
size_t count = 0;
|
||||
|
||||
while (n--) {
|
||||
count += rb_popcount64((uint64_t)ds[n]);
|
||||
}
|
||||
|
||||
return SIZET2NUM(count);
|
||||
}
|
||||
|
||||
VALUE
|
||||
rb_big_odd_p(VALUE num)
|
||||
{
|
||||
|
||||
@@ -123,6 +123,7 @@ VALUE rb_big_aref2(VALUE num, VALUE beg, VALUE len);
|
||||
VALUE rb_big_abs(VALUE x);
|
||||
VALUE rb_big_size_m(VALUE big);
|
||||
VALUE rb_big_bit_length(VALUE big);
|
||||
VALUE rb_big_bit_count(VALUE big);
|
||||
VALUE rb_big_remainder(VALUE x, VALUE y);
|
||||
VALUE rb_big_gt(VALUE x, VALUE y);
|
||||
VALUE rb_big_ge(VALUE x, VALUE y);
|
||||
|
||||
@@ -126,6 +126,7 @@ VALUE rb_int_even_p(VALUE num);
|
||||
VALUE rb_int_odd_p(VALUE num);
|
||||
VALUE rb_int_abs(VALUE num);
|
||||
VALUE rb_int_bit_length(VALUE num);
|
||||
VALUE rb_int_bit_count(VALUE num);
|
||||
VALUE rb_int_uminus(VALUE num);
|
||||
VALUE rb_int_comp(VALUE num);
|
||||
|
||||
|
||||
@@ -5732,6 +5732,49 @@ rb_int_bit_length(VALUE num)
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
rb_fix_bit_count(VALUE fix)
|
||||
{
|
||||
long v = FIX2LONG(fix);
|
||||
if (v < 0)
|
||||
rb_raise(rb_eArgError, "bit_count is undefined for negative integers");
|
||||
return LONG2FIX(rb_popcount_intptr((uintptr_t)v));
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* bit_count -> integer
|
||||
*
|
||||
* Returns the number of set bits (bits equal to 1) in the binary
|
||||
* representation of +self+, also known as the population count or
|
||||
* Hamming weight.
|
||||
*
|
||||
* 0.bit_count # => 0
|
||||
* 1.bit_count # => 1
|
||||
* 7.bit_count # => 3
|
||||
* 0b10101.bit_count # => 3
|
||||
* 255.bit_count # => 8
|
||||
* (2**1000).bit_count # => 1
|
||||
* (2**1000-1).bit_count # => 1000
|
||||
*
|
||||
* Raises an exception if +self+ is negative.
|
||||
*
|
||||
* (-1).bit_count # Raises ArgumentError
|
||||
*
|
||||
*/
|
||||
|
||||
VALUE
|
||||
rb_int_bit_count(VALUE num)
|
||||
{
|
||||
if (FIXNUM_P(num)) {
|
||||
return rb_fix_bit_count(num);
|
||||
}
|
||||
else if (RB_BIGNUM_TYPE_P(num)) {
|
||||
return rb_big_bit_count(num);
|
||||
}
|
||||
UNREACHABLE_RETURN(Qnil);
|
||||
}
|
||||
|
||||
static VALUE
|
||||
rb_fix_digits(VALUE fix, long base)
|
||||
{
|
||||
@@ -6610,6 +6653,7 @@ Init_Numeric(void)
|
||||
rb_define_method(rb_cInteger, ">>", rb_int_rshift, 1);
|
||||
|
||||
rb_define_method(rb_cInteger, "digits", rb_int_digits, -1);
|
||||
rb_define_method(rb_cInteger, "bit_count", rb_int_bit_count, 0);
|
||||
|
||||
#define fix_to_s_static(n) do { \
|
||||
VALUE lit = rb_fstring_literal(#n); \
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
require_relative '../../spec_helper'
|
||||
|
||||
ruby_version_is "4.1" do
|
||||
describe "Integer#bit_count" do
|
||||
it "returns the number of set bits in the binary representation" do
|
||||
0.bit_count.should == 0
|
||||
1.bit_count.should == 1
|
||||
2.bit_count.should == 1
|
||||
3.bit_count.should == 2
|
||||
7.bit_count.should == 3
|
||||
0b10101.bit_count.should == 3
|
||||
0xff.bit_count.should == 8
|
||||
0x100.bit_count.should == 1
|
||||
fixnum_max.bit_count.should == fixnum_max.to_s(2).count("1")
|
||||
|
||||
(2**1000).bit_count.should == 1
|
||||
(2**1000 - 1).bit_count.should == 1000
|
||||
(2**1000 + 2**500).bit_count.should == 2
|
||||
(2**64 - 1).bit_count.should == 64
|
||||
(2**10000 - 1).bit_count.should == 10000
|
||||
end
|
||||
|
||||
it "raises an ArgumentError for a negative number" do
|
||||
-> { -1.bit_count }.should raise_error(ArgumentError)
|
||||
-> { -19.bit_count }.should raise_error(ArgumentError)
|
||||
-> { fixnum_min.bit_count }.should raise_error(ArgumentError)
|
||||
-> { (-2**1000).bit_count }.should raise_error(ArgumentError)
|
||||
-> { (-2**1000 - 1).bit_count }.should raise_error(ArgumentError)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -632,6 +632,41 @@ class TestInteger < Test::Unit::TestCase
|
||||
}
|
||||
end
|
||||
|
||||
def test_bit_count
|
||||
assert_equal(0, 0.bit_count)
|
||||
assert_equal(1, 1.bit_count)
|
||||
assert_equal(1, 2.bit_count)
|
||||
assert_equal(2, 3.bit_count)
|
||||
assert_equal(3, 7.bit_count)
|
||||
assert_equal(3, 0b10101.bit_count)
|
||||
assert_equal(8, 0xff.bit_count)
|
||||
assert_equal(1, 0x100.bit_count)
|
||||
|
||||
# Fixnum boundaries
|
||||
assert_equal(1, (2**30).bit_count)
|
||||
assert_equal(1, (2**62).bit_count)
|
||||
|
||||
# Bignum
|
||||
assert_equal(1, (2**64).bit_count)
|
||||
assert_equal(64, (2**64-1).bit_count)
|
||||
assert_equal(1, (2**1000).bit_count)
|
||||
assert_equal(1000, (2**1000-1).bit_count)
|
||||
assert_equal(2, (2**1000 + 2**500).bit_count)
|
||||
|
||||
0.upto(1000) {|i|
|
||||
n = 2**i
|
||||
assert_equal(1, n.bit_count, "(#{n}).bit_count")
|
||||
assert_equal(i, (n-1).bit_count, "(#{n-1}).bit_count")
|
||||
assert_equal(2, (n+1).bit_count, "(#{n+1}).bit_count") if i >= 1
|
||||
}
|
||||
end
|
||||
|
||||
def test_bit_count_for_negative_numbers
|
||||
assert_raise(ArgumentError) { -1.bit_count }
|
||||
assert_raise(ArgumentError) { -19.bit_count }
|
||||
assert_raise(ArgumentError) { (-2**1000).bit_count }
|
||||
end
|
||||
|
||||
def test_digits
|
||||
assert_equal([0], 0.digits)
|
||||
assert_equal([1], 1.digits)
|
||||
|
||||
Reference in new issue
Block a user