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) )
|
(CCInt.range i j |> Iter.to_list) )
|
||||||
*)
|
*)
|
||||||
|
|
||||||
(*
|
(* popcount comes from [Shims] as it's 32/64 bits dependent, see #327 *)
|
||||||
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 popcount (b:int) : int =
|
||||||
let b = b - ((b lsr 1) land 0x5555555555555555) in
|
let rec loop count x =
|
||||||
let b = (b land 0x3333333333333333) + ((b lsr 2) land 0x3333333333333333) in
|
if x=0 then count
|
||||||
let b = (b + (b lsr 4)) land 0x0f0f0f0f0f0f0f0f in
|
else loop (count+1) (x land (x-1))
|
||||||
let b = b + (b lsr 8) in
|
in
|
||||||
let b = b + (b lsr 16) in
|
loop 0 b
|
||||||
let b = b + (b lsr 32) in
|
|
||||||
b land 0x7f
|
|
||||||
|
|
||||||
(*$=
|
(*$=
|
||||||
0 (popcount 0)
|
0 (popcount 0)
|
||||||
1 (popcount 1)
|
1 (popcount 1)
|
||||||
(Sys.word_size-2) (popcount max_int)
|
(Sys.word_size-2) (popcount max_int)
|
||||||
1 (popcount min_int)
|
1 (popcount min_int)
|
||||||
|
10 (popcount 0b1110010110110001010)
|
||||||
5 (popcount 0b1101110000000000)
|
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}*)
|
(** {{: 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 () =
|
let () =
|
||||||
C.main ~name:"mkshims" (fun c ->
|
C.main ~name:"mkshims" (fun c ->
|
||||||
let version = C.ocaml_config_var_exn c "version" in
|
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_.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 "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 "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'
|
f'
|
||||||
|
|
||||||
(*$R
|
(*$R
|
||||||
let c = unbounded ~eq:CCInt.equal 256 in
|
let c = unbounded ~eq:Int64.equal 256 in
|
||||||
let fib = with_cache_rec c
|
let fib = with_cache_rec c
|
||||||
(fun self n -> match n with
|
(fun self n -> match n with
|
||||||
| 1 | 2 -> 1
|
| 1L | 2L -> 1L
|
||||||
| _ -> self (n-1) + self (n-2)
|
| _ -> CCInt64.(self (n-1L) + self (n-2L))
|
||||||
)
|
)
|
||||||
in
|
in
|
||||||
assert_equal 55 (fib 10);
|
assert_equal 55L (fib 10L);
|
||||||
assert_equal 832040 (fib 30);
|
assert_equal 832040L (fib 30L);
|
||||||
assert_equal 12586269025 (fib 50);
|
assert_equal 12586269025L (fib 50L);
|
||||||
assert_equal 190392490709135 (fib 70)
|
assert_equal 190392490709135L (fib 70L)
|
||||||
*)
|
*)
|
||||||
|
|
||||||
let size c = c.size ()
|
let size c = c.size ()
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue