mirror of
https://github.com/c-cube/ocaml-containers.git
synced 2026-05-05 17:04:25 -04:00
tests for hashes
This commit is contained in:
parent
7fdee4a17e
commit
fe5231a376
1 changed files with 60 additions and 1 deletions
|
|
@ -16,4 +16,63 @@ t @@ fun () -> string "abc" <> string "abcd";;
|
|||
|
||||
q Q.int (fun i ->
|
||||
Q.assume (i >= 0);
|
||||
int i = int64 (Int64.of_int i))
|
||||
int i = int64 (Int64.of_int i));;
|
||||
|
||||
(* --- stress tests -------------------------------------------------------- *)
|
||||
|
||||
(* Chi-squared distribution test over [count] consecutive integers in [buckets] buckets.
|
||||
A uniform hash gives chi2 ~ buckets-1; we allow 4 standard deviations of slack. *)
|
||||
t ~name:"int hash distribution chi2" @@ fun () ->
|
||||
let count = 50_000 and buckets = 500 in
|
||||
let counts = Array.make buckets 0 in
|
||||
for i = 0 to count - 1 do
|
||||
let b = CCHash.int i mod buckets in
|
||||
counts.(b) <- counts.(b) + 1
|
||||
done;
|
||||
let expected = float count /. float buckets in
|
||||
let c2 =
|
||||
Array.fold_left
|
||||
(fun acc c -> acc +. ((float c -. expected) ** 2.0 /. expected))
|
||||
0.0 counts
|
||||
in
|
||||
let df = float (buckets - 1) in
|
||||
c2 < df +. 4.0 *. sqrt (2.0 *. df);;
|
||||
|
||||
(* Strict avalanche criterion: flip one input bit, expect ~50% output bits to change. *)
|
||||
t ~name:"int hash avalanche" @@ fun () ->
|
||||
let bits = Sys.int_size - 1 in
|
||||
let total_flips = ref 0 in
|
||||
let total = ref 0 in
|
||||
let rng = Random.State.make [| 42; 17; 99 |] in
|
||||
for _ = 1 to 300 do
|
||||
let x = Random.State.bits rng in
|
||||
let hx = CCHash.int x in
|
||||
for b = 0 to bits - 1 do
|
||||
let hx' = CCHash.int (x lxor (1 lsl b)) in
|
||||
total_flips := !total_flips + CCInt.popcount (hx lxor hx');
|
||||
total := !total + bits
|
||||
done
|
||||
done;
|
||||
let frac = float !total_flips /. float !total in
|
||||
frac >= 0.45 && frac <= 0.55;;
|
||||
|
||||
(* String hash: no collisions among distinct keys. *)
|
||||
t ~name:"string hash no collisions" @@ fun () ->
|
||||
let n = 50_000 in
|
||||
let tbl = Hashtbl.create n in
|
||||
let ok = ref true in
|
||||
for i = 0 to n - 1 do
|
||||
let h = CCHash.string (Printf.sprintf "key:%d" i) in
|
||||
if Hashtbl.mem tbl h then ok := false;
|
||||
Hashtbl.replace tbl h ()
|
||||
done;
|
||||
!ok;;
|
||||
|
||||
(* CCHash64 pipeline matches CCHash.pair combiner. *)
|
||||
q Q.int (fun i ->
|
||||
let j = i lxor 0xdeadbeef in
|
||||
let h_pair = CCHash.pair CCHash.int CCHash.int (i, j) in
|
||||
let h_manual =
|
||||
CCHash64.(finalize (int (int seed (CCHash.int i)) (CCHash.int j)))
|
||||
in
|
||||
h_pair = h_manual)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue