112 lines
3.4 KiB
OCaml
112 lines
3.4 KiB
OCaml
open! Import
|
|
|
|
module E = struct
|
|
type t =
|
|
{ clz : int
|
|
; ctz : int
|
|
}
|
|
[@@deriving compare, sexp_of]
|
|
end
|
|
|
|
module type T = sig
|
|
type t [@@deriving sexp_of]
|
|
|
|
val one : t
|
|
val ( lsl ) : t -> int -> t
|
|
val clz : t -> int
|
|
val ctz : t -> int
|
|
val num_bits : int
|
|
end
|
|
|
|
module Make (Int : T) = struct
|
|
let%expect_test "one-hot" =
|
|
let clz_and_ctz int = { E.clz = Int.clz int; ctz = Int.ctz int } in
|
|
for i = 0 to Int.num_bits - 1 do
|
|
[%test_result: E.t]
|
|
~expect:{ E.clz = Int.num_bits - 1 - i; ctz = i }
|
|
(clz_and_ctz Int.(one lsl i))
|
|
done
|
|
;;
|
|
end
|
|
|
|
include Make (Nativeint)
|
|
include Make (Int63)
|
|
include Make (Int63.Private.Emul)
|
|
|
|
include Make (struct
|
|
include Int
|
|
|
|
let%expect_test "zero" =
|
|
(* [clz 0] is guaranteed to be num_bits for int. We compute clz on the tagged
|
|
representation of int's, and the binary representation of the int [0] is
|
|
num_bits 0's followed by a 1 (the tag bit). *)
|
|
[%test_result: int] ~expect:num_bits (clz 0)
|
|
;;
|
|
|
|
(* [ctz 0] is unspecified. On linux it seems to be stable and equal to the system
|
|
word size (which is num_bits + 1).
|
|
ran 2019-02-11 on linux:
|
|
{v
|
|
[%test_result: int] ~expect:(num_bits + 1) (ctz 0)
|
|
v}
|
|
|
|
in javascript, it is 32 (which is num_bits):
|
|
ran 2019-02-11 on javascript:
|
|
{v
|
|
[%test_result: int] ~expect:(num_bits) (ctz 0)
|
|
v}
|
|
*)
|
|
end)
|
|
|
|
include Make (struct
|
|
include Int32
|
|
|
|
let clz_and_ctz i32 = { E.clz = clz i32; ctz = ctz i32 }
|
|
|
|
let%expect_test "extra examples" =
|
|
[%test_result: E.t] ~expect:{ clz = 31; ctz = 0 } (clz_and_ctz 0b1l);
|
|
[%test_result: E.t] ~expect:{ clz = 30; ctz = 1 } (clz_and_ctz 0b10l);
|
|
[%test_result: E.t] ~expect:{ clz = 30; ctz = 0 } (clz_and_ctz 0b11l);
|
|
[%test_result: E.t] ~expect:{ clz = 25; ctz = 1 } (clz_and_ctz 0b1000010l);
|
|
[%test_result: E.t]
|
|
~expect:{ clz = 8; ctz = 6 }
|
|
(clz_and_ctz 0b100000010000001001000000l);
|
|
[%test_result: E.t]
|
|
~expect:{ clz = 0; ctz = 31 }
|
|
(clz_and_ctz 0b10000000000000000000000000000000l);
|
|
[%test_result: E.t]
|
|
~expect:{ clz = 9; ctz = 6 }
|
|
(clz_and_ctz 0b00000000010000000100000001000000l);
|
|
[%test_result: E.t]
|
|
~expect:{ clz = 0; ctz = 6 }
|
|
(clz_and_ctz 0b10000000010000000100000001000000l)
|
|
;;
|
|
end)
|
|
|
|
include Make (struct
|
|
include Int64
|
|
|
|
let clz_and_ctz i64 = { E.clz = clz i64; ctz = ctz i64 }
|
|
|
|
let%expect_test "extra examples" =
|
|
[%test_result: E.t] ~expect:{ clz = 63; ctz = 0 } (clz_and_ctz 0b1L);
|
|
[%test_result: E.t] ~expect:{ clz = 62; ctz = 1 } (clz_and_ctz 0b10L);
|
|
[%test_result: E.t] ~expect:{ clz = 62; ctz = 0 } (clz_and_ctz 0b11L);
|
|
[%test_result: E.t] ~expect:{ clz = 57; ctz = 1 } (clz_and_ctz 0b1000010L);
|
|
[%test_result: E.t]
|
|
~expect:{ clz = 40; ctz = 6 }
|
|
(clz_and_ctz 0b100000010000001001000000L);
|
|
[%test_result: E.t]
|
|
~expect:{ clz = 0; ctz = 63 }
|
|
(clz_and_ctz 0b1000000000000000000000000000000000000000000000000000000000000000L);
|
|
[%test_result: E.t]
|
|
~expect:{ clz = 32; ctz = 31 }
|
|
(clz_and_ctz 0b0000000000000000000000000000000010000000000000000000000000000000L);
|
|
[%test_result: E.t]
|
|
~expect:{ clz = 32; ctz = 6 }
|
|
(clz_and_ctz 0b0000000000000000000000000000000010000000010000000100000001000000L);
|
|
[%test_result: E.t]
|
|
~expect:{ clz = 33; ctz = 6 }
|
|
(clz_and_ctz 0b0000000000000000000000000000000001000000010000000100000001000000L)
|
|
;;
|
|
end)
|