Skip to content

Commit

Permalink
Add Int#bit_length (#8924)
Browse files Browse the repository at this point in the history
* Add Int#bit_length

* Update src/int.cr

Co-Authored-By: Vladislav Zarakovsky <vlad.zar@gmail.com>

* Simpler Int#bit_length specs

* Spec for Int#bit_length negative values

* Let Int#bit_length work for BigInt

* More specs...

* Be nice with Windows

Co-authored-by: Vladislav Zarakovsky <vlad.zar@gmail.com>
  • Loading branch information
asterite and vlazar committed Mar 22, 2020
1 parent b2b8498 commit aed65fc
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 1 deletion.
19 changes: 18 additions & 1 deletion spec/std/int_spec.cr
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
require "spec"
require "./spec_helper"
{% unless flag?(:win32) %}
require "big"
{% end %}
Expand Down Expand Up @@ -777,4 +777,21 @@ describe "Int" do
65.unsafe_chr.should eq('A')
(0x10ffff + 1).unsafe_chr.ord.should eq(0x10ffff + 1)
end

describe "#bit_length" do
it "for primitve integers" do
0.bit_length.should eq(0)
0b1.bit_length.should eq(1)
0b1001.bit_length.should eq(4)
0b1001001_i64.bit_length.should eq(7)
0b1111111111.bit_length.should eq(10)
0b1000000000.bit_length.should eq(10)
-1.bit_length.should eq(0)
-10.bit_length.should eq(4)
end

pending_win32 "for BigInt" do
BigInt.new("1234567890123456789012345678901234567890").bit_length.should eq(130)
end
end
end
35 changes: 35 additions & 0 deletions src/int.cr
Original file line number Diff line number Diff line change
Expand Up @@ -395,6 +395,41 @@ struct Int
(self & mask) == mask
end

# Returns the number of bits of this int value.
#
# “The number of bits” means that the bit position of the highest bit
# which is different to the sign bit.
# (The bit position of the bit 2**n is n+1.)
# If there is no such bit (zero or minus one), zero is returned.
#
# I.e. This method returns `ceil(log2(self < 0 ? -self : self + 1))`.
#
# ```
# 0.bit_length # => 0
# 1.bit_length # => 1
# 2.bit_length # => 2
# 3.bit_length # => 2
# 4.bit_length # => 3
# 5.bit_length # => 3
#
# # The above is the same as
# 0b0.bit_length # => 0
# 0b1.bit_length # => 1
# 0b10.bit_length # => 2
# 0b11.bit_length # => 2
# 0b100.bit_length # => 3
# 0b101.bit_length # => 3
# ```
def bit_length : self
x = self < 0 ? ~self : self

if x.is_a?(Int::Primitive)
self.class.new(sizeof(self) * 8 - x.leading_zeros_count)
else
self.class.new(Math.log2(x).to_i + 1)
end
end

# Returns the greatest common divisor of `self` and `other`. Signed
# integers may raise overflow if either has value equal to `MIN` of
# its type.
Expand Down

0 comments on commit aed65fc

Please sign in to comment.