mirror of
https://github.com/c-cube/ocaml-containers.git
synced 2025-12-06 03:05:28 -05:00
fix(int): use shims to provide separate 32/64 bits versions of popcount
close #327
This commit is contained in:
parent
9fe414f793
commit
e0f2c78edd
3 changed files with 59 additions and 35 deletions
|
|
@ -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)
|
||||
*)
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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 ()
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue