mirror of
https://github.com/c-cube/ocaml-containers.git
synced 2025-12-07 03:35:30 -05:00
feat: add Int.popcount operator
This commit is contained in:
parent
4b09adaa5a
commit
d7a7cbb170
2 changed files with 70 additions and 0 deletions
|
|
@ -293,3 +293,69 @@ let range_by ~step i j yield =
|
||||||
(CCInt.range_by ~step:1 i j |> Iter.to_list) \
|
(CCInt.range_by ~step:1 i j |> Iter.to_list) \
|
||||||
(CCInt.range i j |> Iter.to_list) )
|
(CCInt.range i j |> Iter.to_list) )
|
||||||
*)
|
*)
|
||||||
|
|
||||||
|
(*
|
||||||
|
from https://en.wikipedia.org/wiki/Hamming_weight
|
||||||
|
|
||||||
|
//This uses fewer arithmetic operations than any other known
|
||||||
|
//implementation on machines with slow multiplication.
|
||||||
|
//It uses 17 arithmetic operations.
|
||||||
|
int popcount_2(uint64_t x) {
|
||||||
|
x -= (x >> 1) & m1; //put count of each 2 bits into those 2 bits
|
||||||
|
x = (x & m2) + ((x >> 2) & m2); //put count of each 4 bits into those 4 bits
|
||||||
|
x = (x + (x >> 4)) & m4; //put count of each 8 bits into those 8 bits
|
||||||
|
x += x >> 8; //put count of each 16 bits into their lowest 8 bits
|
||||||
|
x += x >> 16; //put count of each 32 bits into their lowest 8 bits
|
||||||
|
x += x >> 32; //put count of each 64 bits into their lowest 8 bits
|
||||||
|
return x & 0x7f;
|
||||||
|
}
|
||||||
|
|
||||||
|
m1 = 0x5555555555555555
|
||||||
|
m2 = 0x3333333333333333
|
||||||
|
m4 = 0x0f0f0f0f0f0f0f0f
|
||||||
|
*)
|
||||||
|
let popcount (b:int) : int =
|
||||||
|
let b = b - ((b lsr 1) land 0x5555555555555555) in
|
||||||
|
let b = (b land 0x3333333333333333) + ((b lsr 2) land 0x3333333333333333) in
|
||||||
|
let b = (b + (b lsr 4)) land 0x0f0f0f0f0f0f0f0f in
|
||||||
|
let b = b + (b lsr 8) in
|
||||||
|
let b = b + (b lsr 16) in
|
||||||
|
let b = b + (b lsr 32) in
|
||||||
|
b land 0x7f
|
||||||
|
|
||||||
|
(*$=
|
||||||
|
0 (popcount 0)
|
||||||
|
1 (popcount 1)
|
||||||
|
(Sys.word_size-2) (popcount max_int)
|
||||||
|
1 (popcount min_int)
|
||||||
|
5 (popcount 0b1101110000000000)
|
||||||
|
*)
|
||||||
|
|
||||||
|
(*$inject
|
||||||
|
let simple_popcnt i =
|
||||||
|
let rec loop n i =
|
||||||
|
if i=0 then n
|
||||||
|
else if i land 0b1 = 1 then loop (n+1) (i lsr 1)
|
||||||
|
else loop n (i lsr 1)
|
||||||
|
in
|
||||||
|
loop 0 i
|
||||||
|
*)
|
||||||
|
|
||||||
|
(*$=
|
||||||
|
0 (simple_popcnt 0)
|
||||||
|
1 (simple_popcnt 1)
|
||||||
|
(Sys.word_size-2) (simple_popcnt max_int)
|
||||||
|
1 (simple_popcnt min_int)
|
||||||
|
5 (simple_popcnt 0b1101110000000000)
|
||||||
|
*)
|
||||||
|
|
||||||
|
(*$QR & ~count:3_000 ~long_factor:10
|
||||||
|
Q.(let g = int in
|
||||||
|
set_gen (Gen.graft_corners g.gen [min_int; max_int; 0; -1; 1] ()) g)
|
||||||
|
(fun i ->
|
||||||
|
if simple_popcnt i <> popcount i then (
|
||||||
|
Q.Test.fail_reportf "on %d: simple-popcount=%d, popcount=%d"
|
||||||
|
i (simple_popcnt i) (popcount i)
|
||||||
|
);
|
||||||
|
true)
|
||||||
|
*)
|
||||||
|
|
|
||||||
|
|
@ -105,6 +105,10 @@ val range' : t -> t -> t iter
|
||||||
For instance [range' 0 5 = Iter.of_list [0;1;2;3;4]].
|
For instance [range' 0 5 = Iter.of_list [0;1;2;3;4]].
|
||||||
@since 1.2 *)
|
@since 1.2 *)
|
||||||
|
|
||||||
|
val popcount : t -> int
|
||||||
|
(** Number of bits set to 1
|
||||||
|
@since NEXT_RELEASE *)
|
||||||
|
|
||||||
(** {2 Infix Operators}
|
(** {2 Infix Operators}
|
||||||
|
|
||||||
@since 0.17 *)
|
@since 0.17 *)
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue