feat(CCInt32): add popcount function

This commit is contained in:
Simon Cruanes 2022-01-02 21:42:59 -05:00
parent 22bbe23c5a
commit b8c93f42fa
No known key found for this signature in database
GPG key ID: 4AC01D0849AA62B6
2 changed files with 34 additions and 0 deletions

View file

@ -32,6 +32,36 @@ let pow a b =
pow 0l 1l = 0l pow 0l 1l = 0l
*) *)
(* see {!CCInt.popcount} for more details *)
let[@inline] popcount (b:t) : int =
let m1 = 0x55555555l in
let m2 = 0x33333333l in
let m4 = 0x0f0f0f0fl in
let b = sub b (logand (shift_right_logical b 1) m1) in
let b = add (logand b m2) (logand (shift_right_logical b 2) m2) in
let b = logand (add b (shift_right_logical b 4)) m4 in
let b = add b (shift_right_logical b 8) in
let b = add b (shift_right_logical b 16) in
let b = logand b 0x7fl in
to_int b
(*$Q
Q.(0 -- (Int32.max_int |> Int32.to_int)) (fun i -> \
let n1 = CCInt.popcount i in \
let n2 = CCInt32.popcount (Int32.of_int i) in \
CCInt.(n1 = n2))
*)
(*$= & ~printer:CCInt.to_string
0 (popcount 0l)
1 (popcount 1l)
31 (popcount max_int)
1 (popcount min_int)
10 (popcount 0b1110010110110001010l)
5 (popcount 0b1101110000000000l)
*)
let floor_div a n = let floor_div a n =
if compare a 0l < 0 && compare n 0l >= 0 then if compare a 0l < 0 && compare n 0l >= 0 then
sub (div (add a 1l) n) 1l sub (div (add a 1l) n) 1l

View file

@ -41,6 +41,10 @@ val pow : t -> t -> t
Raises [Invalid_argument] if [x = y = 0] or [y] < 0. Raises [Invalid_argument] if [x = y = 0] or [y] < 0.
@since 0.11 *) @since 0.11 *)
val popcount : t -> int
(** Number of bits set to 1.
@since NEXT_RELEASE *)
val floor_div : t -> t -> t val floor_div : t -> t -> t
(** [floor_div x n] is integer division rounding towards negative infinity. (** [floor_div x n] is integer division rounding towards negative infinity.
It satisfies [x = m * floor_div x n + rem x n]. It satisfies [x = m * floor_div x n + rem x n].