Skip to content

Commit

Permalink
Add Random.int63
Browse files Browse the repository at this point in the history
Behaves equivalently on 64-bit and JavaScript and allows 62-bit
upperbound on 64-bit systems.
  • Loading branch information
dra27 committed Apr 23, 2020
1 parent 1ff77b8 commit d1c4122
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 10 deletions.
5 changes: 3 additions & 2 deletions Changes
Original file line number Diff line number Diff line change
Expand Up @@ -220,8 +220,9 @@ OCaml 4.12.0

### Standard library:

- #9487, #9489: Random.int now accepts 62-bit bounds on 64-bit systems.
(David Allsopp, request by Francois Berenger, review by Xavier Leroy)
- #9487, #9489: Add Random.int63 which allows 62-bit bounds on 64-bit systems.
(David Allsopp, request by Francois Berenger, review by Xavier Leroy and
Damien Doligez)

- #9865: add Format.pp_print_seq
(Raphaël Proust, review by Nicolás Ojeda Bär)
Expand Down
25 changes: 20 additions & 5 deletions stdlib/random.ml
Original file line number Diff line number Diff line change
Expand Up @@ -88,17 +88,31 @@ module State = struct
let v = r mod n in
if r - v > 0x3FFFFFFF - n + 1 then intaux s n else v

let int s bound =
if bound > 0x3FFFFFFF || bound <= 0
then invalid_arg "Random.int"
else intaux s bound

let rec int63aux s n =
let max_int_32 = (1 lsl 30) + 0x3FFFFFFF in (* 0x7FFFFFFF *)
let b1 = bits s in
let b2 = bits s lsl 30 in
let b3 = (bits s land 3) lsl 60 in
let r = b1 lor b2 lor b3 in
let b2 = bits s in
let (b, max_int) =
if n <= max_int_32 then
(* 32 random bits on both 64-bit OCaml and JavaScript *)
((((b2 land 0x30000000) lsl 2) lor b1) land max_int_32, max_int_32)
else
let b3 = bits s in
(* 63 random bits on 64-bit OCaml; unreachable on JavaScript *)
(((((b3 land 0x38000000) lsl 3) lor b2) lsl 30) lor b1, max_int)
in
let r = b lsr 1 in (* Random non-negative int *)
let v = r mod n in
if r - v > max_int - n + 1 then int63aux s n else v

let int s bound =
let int63 s bound =
if bound <= 0 then
invalid_arg "Random.int"
invalid_arg "Random.int63"
else if bound > 0x3FFFFFFF then
int63aux s bound
else
Expand Down Expand Up @@ -176,6 +190,7 @@ let default = {

let bits () = State.bits default
let int bound = State.int default bound
let int63 bound = State.int63 default bound
let int32 bound = State.int32 default bound
let nativeint bound = State.nativeint default bound
let int64 bound = State.int64 default bound
Expand Down
16 changes: 13 additions & 3 deletions stdlib/random.mli
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,19 @@ val bits : unit -> int

val int : int -> int
(** [Random.int bound] returns a random integer between 0 (inclusive)
and [bound] (exclusive). [bound] must be greater than 0 and less
than {!Stdlib.max_int}
and [bound] (exclusive). [bound] must be greater than 0 and less
than 2{^30}. *)

@before 4.12.0 [bound] had to be less than 2{^30}. *)
val int63 : int -> int
(** [Random.int63 bound] returns a random integer between 0 (inclusive)
and [bound] (exclusive). [bound] may be any positive integer.
If [bound] is less than 2{^30}, [Random.int63 bound] is equal to
{!Random.int}[ bound]. If [bound] is greater than 2{^30} (on 64-bit systems
or non-standard environments, such as JavaScript), [Random.int63] returns
a value, where {!Random.int} raises {!Invalid_argument}.
@since 4.12.0 *)

val int32 : Int32.t -> Int32.t
(** [Random.int32 bound] returns a random integer between 0 (inclusive)
Expand Down Expand Up @@ -91,6 +100,7 @@ module State : sig

val bits : t -> int
val int : t -> int -> int
val int63 : t -> int -> int
val int32 : t -> Int32.t -> Int32.t
val nativeint : t -> Nativeint.t -> Nativeint.t
val int64 : t -> Int64.t -> Int64.t
Expand Down

0 comments on commit d1c4122

Please sign in to comment.