From e0f2c78eddc8837dd5a8bdcd61dc720350a4e211 Mon Sep 17 00:00:00 2001 From: Simon Cruanes Date: Wed, 5 Aug 2020 14:05:48 -0400 Subject: [PATCH] fix(int): use shims to provide separate 32/64 bits versions of popcount close #327 --- src/core/CCInt.ml | 34 +++++++-------------------------- src/core/mkshims.ml | 46 ++++++++++++++++++++++++++++++++++++++++++++- src/data/CCCache.ml | 14 +++++++------- 3 files changed, 59 insertions(+), 35 deletions(-) diff --git a/src/core/CCInt.ml b/src/core/CCInt.ml index 5f1b49ae..932f8525 100644 --- a/src/core/CCInt.ml +++ b/src/core/CCInt.ml @@ -319,40 +319,20 @@ let range_by ~step i j yield = (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 -*) +(* popcount comes from [Shims] as it's 32/64 bits dependent, see #327 *) 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 + let rec loop count x = + if x=0 then count + else loop (count+1) (x land (x-1)) + in + loop 0 b (*$= 0 (popcount 0) 1 (popcount 1) (Sys.word_size-2) (popcount max_int) 1 (popcount min_int) + 10 (popcount 0b1110010110110001010) 5 (popcount 0b1101110000000000) *) diff --git a/src/core/mkshims.ml b/src/core/mkshims.ml index 340a6114..ace45bfb 100644 --- a/src/core/mkshims.ml +++ b/src/core/mkshims.ml @@ -170,6 +170,48 @@ let shims_int_post_408 = " (** {{: https://caml.inria.fr/pub/docs/manual-ocaml/libref/Int.html} Documentation for the standard Int module}*) " +let shims_int_64bit = " +(* + 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 +" + +let shims_int_32bit = " +(* we use the simple version for 32 bits. *) +let popcount (b:int) : int = + let rec loop count x = + if x=0 then count + else loop (count+1) (x land (x-1)) + in + loop 0 b + +" + let () = C.main ~name:"mkshims" (fun c -> let version = C.ocaml_config_var_exn c "version" in @@ -188,5 +230,7 @@ let () = write_file "CCShimsFun_.ml" (if (major, minor) >= (4,8) then shims_fun_post_408 else shims_fun_pre_408); write_file "CCShimsFun_.mli" (if (major, minor) >= (4,8) then shims_fun_mli_post_408 else shims_fun_mli_pre_408); write_file "CCShimsMkLet_.ml" (if (major, minor) >= (4,8) then shims_let_op_post_408 else shims_let_op_pre_408); - write_file "CCShimsInt_.ml" (if (major, minor) >= (4,8) then shims_int_post_408 else shims_int_pre_408); + write_file "CCShimsInt_.ml" + ((if (major, minor) >= (4,8) then shims_int_post_408 else shims_int_pre_408) + ^ if Sys.word_size=32 then shims_int_32bit else shims_int_64bit); ) diff --git a/src/data/CCCache.ml b/src/data/CCCache.ml index 4de7e637..b7a58bc0 100644 --- a/src/data/CCCache.ml +++ b/src/data/CCCache.ml @@ -56,17 +56,17 @@ let with_cache_rec ?(cb=default_callback_) c f = f' (*$R - let c = unbounded ~eq:CCInt.equal 256 in + let c = unbounded ~eq:Int64.equal 256 in let fib = with_cache_rec c (fun self n -> match n with - | 1 | 2 -> 1 - | _ -> self (n-1) + self (n-2) + | 1L | 2L -> 1L + | _ -> CCInt64.(self (n-1L) + self (n-2L)) ) in - assert_equal 55 (fib 10); - assert_equal 832040 (fib 30); - assert_equal 12586269025 (fib 50); - assert_equal 190392490709135 (fib 70) + assert_equal 55L (fib 10L); + assert_equal 832040L (fib 30L); + assert_equal 12586269025L (fib 50L); + assert_equal 190392490709135L (fib 70L) *) let size c = c.size ()