Skip to content

Commit

Permalink
Implement Int#{leading,trailing}_zeros_count
Browse files Browse the repository at this point in the history
  • Loading branch information
Sija committed Mar 19, 2019
1 parent d4ded5c commit 3c7e154
Show file tree
Hide file tree
Showing 6 changed files with 128 additions and 0 deletions.
4 changes: 4 additions & 0 deletions spec/std/big/big_int_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,10 @@ describe "BigInt" do
5.to_big_i.popcount.should eq(2)
end

it "#trailing_zeros_count" do
"00000000000000001000000000001000".to_big_i(base: 2).trailing_zeros_count.should eq(3)
end

it "#hash" do
b1 = 5.to_big_i
b2 = 5.to_big_i
Expand Down
16 changes: 16 additions & 0 deletions spec/std/int_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -646,6 +646,22 @@ describe "Int" do
it { 18446744073709551615_u64.popcount.should eq(64) }
end

describe "#leading_zeros_count" do
{% for width in %w(8 16 32 64).map(&.id) %}
it { -1_i{{width}}.leading_zeros_count.should eq(0) }
it { 0_i{{width}}.leading_zeros_count.should eq({{width}}) }
it { 0_u{{width}}.leading_zeros_count.should eq({{width}}) }
{% end %}
end

describe "#trailing_zeros_count" do
{% for width in %w(8 16 32 64).map(&.id) %}
it { -2_i{{width}}.trailing_zeros_count.should eq(1) }
it { 2_i{{width}}.trailing_zeros_count.should eq(1) }
it { 2_u{{width}}.trailing_zeros_count.should eq(1) }
{% end %}
end

it "compares signed vs. unsigned integers" do
signed_ints = [Int8::MAX, Int16::MAX, Int32::MAX, Int64::MAX, Int8::MIN, Int16::MIN, Int32::MIN, Int64::MIN, 0_i8, 0_i16, 0_i32, 0_i64]
unsigned_ints = [UInt8::MAX, UInt16::MAX, UInt32::MAX, UInt64::MAX, 0_u8, 0_u16, 0_u32, 0_u64]
Expand Down
8 changes: 8 additions & 0 deletions src/big/big_int.cr
Original file line number Diff line number Diff line change
Expand Up @@ -385,6 +385,14 @@ struct BigInt < Int
LibGMP.popcount(self)
end

def leading_zeros_count
{% raise "No BigInt implementation available" %}
end

def trailing_zeros_count
LibGMP.scan1(self, 0)
end

def to_i
to_i32
end
Expand Down
2 changes: 2 additions & 0 deletions src/big/lib_gmp.cr
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,8 @@ lib LibGMP
# # Logic

fun popcount = __gmpz_popcount(op : MPZ*) : BitcntT
fun scan0 = __gmpz_scan0(op : MPZ*, starting_bit : BitcntT) : BitcntT
fun scan1 = __gmpz_scan1(op : MPZ*, starting_bit : BitcntT) : BitcntT

# # Comparison

Expand Down
86 changes: 86 additions & 0 deletions src/int.cr
Original file line number Diff line number Diff line change
Expand Up @@ -542,6 +542,12 @@ struct Int
# ```
abstract def popcount

# Returns the number of leading `0`-bits.
# abstract def leading_zeros_count

# Returns the number of trailing `0`-bits.
abstract def trailing_zeros_count

private class TimesIterator(T)
include Iterator(T)

Expand Down Expand Up @@ -629,6 +635,14 @@ struct Int8
Intrinsics.popcount8(self)
end

def leading_zeros_count
Intrinsics.countleading8(self, false)
end

def trailing_zeros_count
Intrinsics.counttrailing8(self, false)
end

def clone
self
end
Expand Down Expand Up @@ -656,6 +670,14 @@ struct Int16
Intrinsics.popcount16(self)
end

def leading_zeros_count
Intrinsics.countleading16(self, false)
end

def trailing_zeros_count
Intrinsics.counttrailing16(self, false)
end

def clone
self
end
Expand Down Expand Up @@ -683,6 +705,14 @@ struct Int32
Intrinsics.popcount32(self)
end

def leading_zeros_count
Intrinsics.countleading32(self, false)
end

def trailing_zeros_count
Intrinsics.counttrailing32(self, false)
end

def clone
self
end
Expand Down Expand Up @@ -710,6 +740,14 @@ struct Int64
Intrinsics.popcount64(self)
end

def leading_zeros_count
Intrinsics.countleading64(self, false)
end

def trailing_zeros_count
Intrinsics.counttrailing64(self, false)
end

def clone
self
end
Expand Down Expand Up @@ -739,6 +777,14 @@ struct Int128
Intrinsics.popcount128(self)
end

def leading_zeros_count
Intrinsics.countleading128(self, false)
end

def trailing_zeros_count
Intrinsics.counttrailing128(self, false)
end

def clone
self
end
Expand Down Expand Up @@ -766,6 +812,14 @@ struct UInt8
Intrinsics.popcount8(self)
end

def leading_zeros_count
Intrinsics.countleading8(self, false)
end

def trailing_zeros_count
Intrinsics.counttrailing8(self, false)
end

def clone
self
end
Expand Down Expand Up @@ -793,6 +847,14 @@ struct UInt16
Intrinsics.popcount16(self)
end

def leading_zeros_count
Intrinsics.countleading16(self, false)
end

def trailing_zeros_count
Intrinsics.counttrailing16(self, false)
end

def clone
self
end
Expand Down Expand Up @@ -820,6 +882,14 @@ struct UInt32
Intrinsics.popcount32(self)
end

def leading_zeros_count
Intrinsics.countleading32(self, false)
end

def trailing_zeros_count
Intrinsics.counttrailing32(self, false)
end

def clone
self
end
Expand Down Expand Up @@ -847,6 +917,14 @@ struct UInt64
Intrinsics.popcount64(self)
end

def leading_zeros_count
Intrinsics.countleading64(self, false)
end

def trailing_zeros_count
Intrinsics.counttrailing64(self, false)
end

def clone
self
end
Expand Down Expand Up @@ -875,6 +953,14 @@ struct UInt128
Intrinsics.popcount128(self)
end

def leading_zeros_count
Intrinsics.countleading128(self, false)
end

def trailing_zeros_count
Intrinsics.counttrailing128(self, false)
end

def clone
self
end
Expand Down
12 changes: 12 additions & 0 deletions src/intrinsics.cr
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,18 @@ lib Intrinsics
fun popcount64 = "llvm.ctpop.i64"(src : Int64) : Int64
fun popcount128 = "llvm.ctpop.i128"(src : Int128) : Int128

fun countleading8 = "llvm.ctlz.i8"(src : Int8, zero_is_undef : Bool) : Int8
fun countleading16 = "llvm.ctlz.i16"(src : Int16, zero_is_undef : Bool) : Int16
fun countleading32 = "llvm.ctlz.i32"(src : Int32, zero_is_undef : Bool) : Int32
fun countleading64 = "llvm.ctlz.i64"(src : Int64, zero_is_undef : Bool) : Int64
fun countleading128 = "llvm.ctlz.i128"(src : Int128, zero_is_undef : Bool) : Int128

fun counttrailing8 = "llvm.cttz.i8"(src : Int8, zero_is_undef : Bool) : Int8
fun counttrailing16 = "llvm.cttz.i16"(src : Int16, zero_is_undef : Bool) : Int16
fun counttrailing32 = "llvm.cttz.i32"(src : Int32, zero_is_undef : Bool) : Int32
fun counttrailing64 = "llvm.cttz.i64"(src : Int64, zero_is_undef : Bool) : Int64
fun counttrailing128 = "llvm.cttz.i128"(src : Int128, zero_is_undef : Bool) : Int128

fun va_start = "llvm.va_start"(ap : Void*)
fun va_end = "llvm.va_end"(ap : Void*)
end
Expand Down

0 comments on commit 3c7e154

Please sign in to comment.