From b8c93f42fab2fd0ee006c9f699a14200b9a9c3ce Mon Sep 17 00:00:00 2001 From: Simon Cruanes Date: Sun, 2 Jan 2022 21:42:59 -0500 Subject: [PATCH] feat(CCInt32): add popcount function --- src/core/CCInt32.ml | 30 ++++++++++++++++++++++++++++++ src/core/CCInt32.mli | 4 ++++ 2 files changed, 34 insertions(+) diff --git a/src/core/CCInt32.ml b/src/core/CCInt32.ml index 2abe36cd..642b6daa 100644 --- a/src/core/CCInt32.ml +++ b/src/core/CCInt32.ml @@ -32,6 +32,36 @@ let pow a b = 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 = if compare a 0l < 0 && compare n 0l >= 0 then sub (div (add a 1l) n) 1l diff --git a/src/core/CCInt32.mli b/src/core/CCInt32.mli index 3dd383cb..95efe38b 100644 --- a/src/core/CCInt32.mli +++ b/src/core/CCInt32.mli @@ -41,6 +41,10 @@ val pow : t -> t -> t Raises [Invalid_argument] if [x = y = 0] or [y] < 0. @since 0.11 *) +val popcount : t -> int +(** Number of bits set to 1. + @since NEXT_RELEASE *) + val floor_div : t -> t -> t (** [floor_div x n] is integer division rounding towards negative infinity. It satisfies [x = m * floor_div x n + rem x n].