5
5
SPDX-License-Identifier: BSD-3-Clause *)
6
6
open Stdint
7
7
8
+ module U128 = struct
9
+ type t = { high : uint64 ; low : uint64 }
10
+
11
+ let of_u64 high low = {high; low}
12
+
13
+ let one = Uint64. {high = zero; low = one}
14
+
15
+ let zero = Uint64. {high = zero; low = zero}
16
+
17
+ let ( + ) a b =
18
+ match Uint64. {high = a.high + b.high; low = a.low + b.low} with
19
+ | x when x.low < b.low -> {x with high = Uint64. (x.high + one)}
20
+ | x -> x
21
+
22
+ let max32 = Uint32. (max_int |> to_uint64)
23
+ let mult64 x y =
24
+ let open Uint64 in
25
+ let x0 = logand max32 x and y0 = logand max32 y
26
+ and x1 = shift_right x 32 and y1 = shift_right y 32 in
27
+ let t = shift_right (x0 * y0) 32 + x1 * y0 in
28
+ {high = shift_right (logand max32 t + x0 * y1) 32 + (shift_right t 32 ) + x1 * y1; low = x * y}
29
+
30
+ let ( * ) a b = match mult64 a.low b.low with
31
+ | {high;low} -> {high = Uint64. (high + a.high * b.low + a.low * b.high); low}
32
+
33
+ (* let ( ** ) a b = match mult64 a.low b with
34
+ | x -> {x with high = Uint64.(x.high + a.high * b)} *)
35
+ end
36
+
8
37
9
38
module PCG64 : sig
10
39
(* * PCG-64 is a 128-bit implementation of O'Neill's permutation congruential
@@ -20,7 +49,7 @@ module PCG64 : sig
20
49
21
50
include Common. BITGEN
22
51
23
- val advance : int128 -> t -> t
52
+ val advance : uint64 * uint64 -> t -> t
24
53
(* * [advance delta] Advances the underlying RNG as if [delta] draws have been made.
25
54
The returned state is that of the generator [delta] steps forward. *)
26
55
@@ -29,55 +58,60 @@ module PCG64 : sig
29
58
(0, bound) as well as the state of the generator advanced one step forward. *)
30
59
end = struct
31
60
type t = {s : setseq ; ustore : uint32 option }
32
- and setseq = {state : uint128 ; increment : uint128 }
61
+ and setseq = {state : U128 .t ; increment : U128 .t }
62
+
63
+
64
+ let sixtythree = Uint32. of_int32 63l
65
+ let multiplier = U128. of_u64 (Uint64. of_int64 2549297995355413924L )
66
+ (Uint64. of_int64 4865540595714422341L )
33
67
34
- let multiplier = Uint128. of_string " 0x2360ed051fc65da44385df649fccf645"
35
- let sixtythree = Uint32. of_int 63
36
68
37
69
(* Uses the XSL-RR output function *)
38
- let output state =
39
- let v = Uint128. (shift_right state 64 |> logxor state |> to_uint64)
40
- and r = Uint128 . (shift_right state 122 |> to_int) in
41
- let nr = Uint32. (of_int r |> neg |> logand sixtythree |> to_int) in
42
- Uint64. (logor (shift_left v nr) (shift_right v r))
43
-
70
+ let output U128. {high; low} =
71
+ let v = Uint64. ( logxor high low) in
72
+ let r = Uint64 . (shift_right high 58 |> to_int) in
73
+ let nr = Uint32. (of_int r |> neg |> logand sixtythree |> to_int) in
74
+ Uint64. (logor (shift_left v nr) (shift_right v r))
75
+
44
76
45
77
let next {state; increment} =
46
- let state' = Uint128 . (state * multiplier + increment) in
78
+ let state' = U128 . (state * multiplier + increment) in
47
79
output state', {state = state'; increment}
48
80
49
81
50
82
let next_uint64 t = match next t.s with
51
83
| u , s -> u, {t with s}
52
-
84
+
53
85
54
86
let next_uint32 t =
55
87
match Common. next_uint32 ~next: next t.s t.ustore with
56
- | u , s , ustore -> u, {s; ustore}
88
+ | u , s , ustore -> u, {s; ustore}
57
89
58
90
59
- let next_double t = Common. next_double ~nextu64: next_uint64 t
91
+ let next_bounded_uint64 bound t = Common. next_bounded_uint64 bound ~nextu64: next_uint64 t
60
92
61
93
62
- let advance delta {s = {state; increment} ; _} =
63
- let open Uint128 in
64
- let rec lcg d am ap cm cp = (* advance state using LCG method *)
65
- match d = zero, logand d one = one with
66
- | true , _ -> am * state + ap
67
- | false , true -> lcg (shift_right d 1 ) (am * cm) (ap * cm + cp) (cm * cm) (cp * (cm + one))
68
- | false , false -> lcg (shift_right d 1 ) am ap (cm * cm) (cp * (cm + one))
69
- in {s = {state = lcg (Uint128. of_int128 delta) one zero multiplier increment; increment}; ustore = None }
94
+ let next_double t = Common. next_double ~nextu64: next_uint64 t
70
95
71
96
72
97
let set_seed seed =
73
- let open Uint128 in
74
- let s = logor (shift_left (of_uint64 seed.(0 )) 64 ) (of_uint64 seed.(1 ))
75
- and i = logor (shift_left (of_uint64 seed.(2 )) 64 ) (of_uint64 seed.(3 )) in
76
- let increment = logor (shift_left i 1 ) one in
77
- {state = (increment + s) * multiplier + increment; increment}
78
-
79
-
80
- let next_bounded_uint64 bound t = Common. next_bounded_uint64 bound ~nextu64: next_uint64 t
98
+ let s2 = Uint64. (logor (shift_left seed.(2 ) 1 ) (shift_right seed.(3 ) 63 )) in
99
+ let s3 = Uint64. (logor (shift_left seed.(3 ) 1 ) one) in
100
+ let increment = U128. of_u64 s2 s3 in
101
+ let state = U128. (zero * multiplier + increment) in
102
+ {state = U128. ((of_u64 seed.(0 ) seed.(1 ) + state) * multiplier + increment); increment}
103
+
104
+
105
+ let advance (d1 , d0 ) {s = {state; increment} ; _} =
106
+ let open U128 in
107
+ let half x = U128. {low = Uint64. (logor (shift_right x.low 1 ) (shift_left x.high 63 ));
108
+ high = Uint64. (shift_right x.high 1 )} in
109
+ let rec lcg d am ap cm cp =
110
+ match Uint64. (d.high < = zero && d.low < = zero, logand d.low one = one) with
111
+ | true , _ -> am * state + ap
112
+ | false , true -> lcg (half d) (am * cm) (ap * cm + cp) (cm * cm) (cp * (cm + one))
113
+ | false , false -> lcg (half d) am ap (cm * cm) (cp * (cm + one))
114
+ in {s = {state = lcg (of_u64 d1 d0) one zero multiplier increment; increment}; ustore = None }
81
115
82
116
83
117
let initialize seed =
0 commit comments