1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
|
/**************************************************************************/
/* */
/* OCaml */
/* */
/* Xavier Leroy, projet Cambium, College de France and Inria */
/* */
/* Copyright 2021 Institut National de Recherche en Informatique et */
/* en Automatique. */
/* */
/* All rights reserved. This file is distributed under the terms of */
/* the GNU Lesser General Public License version 2.1, with the */
/* special exception on linking described in the file LICENSE. */
/* */
/**************************************************************************/
#include <string.h>
#include "caml/alloc.h"
#include "caml/bigarray.h"
#include "caml/mlvalues.h"
/* The L64X128 member of the LXM family. Taken from figure 1 in
"LXM: Better Splittable Pseudorandom Number Generators
(and Almost as Fast)" by Guy L. Steele Jr. and Sebastiano Vigna,
OOPSLA 2021. */
static const uint64_t M = 0xd1342543de82ef95;
struct LXM_state {
uint64_t a; /* per-instance additive parameter (odd) */
uint64_t s; /* state of the LCG subgenerator */
uint64_t x[2]; /* state of the XBG subgenerator (not 0) */
};
/* In OCaml, states are represented as a 1D big array of 64-bit integers */
#define LXM_val(v) ((struct LXM_state *) Caml_ba_data_val(v))
#ifndef Caml_inline
// Define Caml_inline for OCaml <= 4.12
#if defined(_MSC_VER) && !defined(__cplusplus)
#define Caml_inline static __inline
#else
#define Caml_inline static inline
#endif
#endif
Caml_inline uint64_t rotl(const uint64_t x, int k) {
return (x << k) | (x >> (64 - k));
}
CAMLprim uint64_t caml_lxm_next_unboxed(value v)
{
uint64_t z, q0, q1;
struct LXM_state * st = LXM_val(v);
/* Combining operation */
z = st->s + st->x[0];
/* Mixing function */
z = (z ^ (z >> 32)) * 0xdaba0b6eb09322e3;
z = (z ^ (z >> 32)) * 0xdaba0b6eb09322e3;
z = (z ^ (z >> 32));
/* LCG update */
st->s = st->s * M + st->a;
/* XBG update */
q0 = st->x[0]; q1 = st->x[1];
q1 ^= q0;
q0 = rotl(q0, 24);
q0 = q0 ^ q1 ^ (q1 << 16);
q1 = rotl(q1, 37);
st->x[0] = q0; st->x[1] = q1;
/* Return result */
return z;
}
CAMLprim value caml_lxm_next(value v)
{
return caml_copy_int64(caml_lxm_next_unboxed(v));
}
|