Skip to content

Commit

Permalink
Use JFS64 instead of TinyMT64 as our PRNG
Browse files Browse the repository at this point in the history
The Mersenne Twister is now a bit outdated and there are alternatives
that are both faster and have better statistical properties.
  • Loading branch information
MasterDuke17 committed Mar 13, 2022
1 parent 588e00d commit 1550dc7
Show file tree
Hide file tree
Showing 11 changed files with 46 additions and 203 deletions.
30 changes: 0 additions & 30 deletions 3rdparty/tinymt/LICENSE.txt

This file was deleted.

11 changes: 0 additions & 11 deletions 3rdparty/tinymt/README.txt

This file was deleted.

133 changes: 0 additions & 133 deletions 3rdparty/tinymt/tinymt64.c

This file was deleted.

3 changes: 0 additions & 3 deletions 3rdparty/tinymt/tinymt64.h

This file was deleted.

1 change: 0 additions & 1 deletion LICENSE
Expand Up @@ -28,6 +28,5 @@ Unofficial summary of the intended application of the Artistic License 2.0:
- libuv MIT,BSD,ISC
- msinttypes MIT
- sha1 Public Domain
- tinymt MIT
- freebsd MIT
- mimalloc MIT
7 changes: 1 addition & 6 deletions build/Makefile.in
Expand Up @@ -41,7 +41,6 @@ CFLAGS = @cflags@ @ccdef@MVM_TRACING=$(TRACING) @ccdef@MVM_CGOTO=$(CGOTO)
CINCLUDES = @moar_cincludes@ \
@ccinc@@shaincludedir@ \
@mimalloc_include@ \
@ccincsystem@3rdparty/tinymt \
@ccincsystem@3rdparty/ryu \
@ccincsystem@3rdparty/dynasm \
@ccincsystem@3rdparty/cmp \
Expand Down Expand Up @@ -302,6 +301,7 @@ HEADERS = src/moar.h \
src/core/intcache.h \
src/core/fixedsizealloc.h \
src/core/regionalloc.h \
src/core/jfs64.h \
src/debug/debugserver.h \
src/io/io.h \
src/io/eventloop.h \
Expand Down Expand Up @@ -721,10 +721,6 @@ tools/repr_size_table@exe@: tools/repr_size_table@obj@ @moarlib@ $(DLL_LIBS)
$(MSG) linking $@
$(CMD)@sharule@ $(NOOUT)

@mtlib@: @mtobjects@
$(MSG) linking $@
$(CMD)@mtrule@ $(NOOUT)

@cmplib@: @cmpobjects@
$(MSG) linking $@
$(CMD)@cmprule@ $(NOOUT)
Expand Down Expand Up @@ -754,7 +750,6 @@ realclean: clean
-$(RM) @laolib@ $(NOOUT) $(NOERR)
-$(CMD)@tomclean@ $(NOOUT) $(NOERR)
-$(CMD)@shaclean@ $(NOOUT) $(NOERR)
-$(CMD)@mtclean@ $(NOOUT) $(NOERR)
-$(CMD)@dcclean@ $(NOOUT) $(NOERR)
-$(CMD)@cmpclean@ $(NOOUT) $(NOERR)
-$(RM) $(MINILUA) $(NOOUT) $(NOERR)
Expand Down
7 changes: 0 additions & 7 deletions build/setup.pm
Expand Up @@ -26,12 +26,6 @@ my %TP_TOM = (
src => [ '3rdparty/libtommath' ],
);

my %TP_MT = (
name => 'tinymt',
path => '3rdparty/tinymt',
src => [ '3rdparty/tinymt' ],
);

my %TP_DC = (
name => 'dyncall_s',
path => '3rdparty/dyncall/dyncall',
Expand Down Expand Up @@ -77,7 +71,6 @@ our %THIRDPARTY = (
lao => { %TP_LAO },
tom => { %TP_TOM },
sha => { %TP_SHA },
mt => { %TP_MT },
dc => { %TP_DC },
dcb => { %TP_DCB },
dl => { %TP_DL },
Expand Down
34 changes: 34 additions & 0 deletions src/core/jfs64.h
@@ -0,0 +1,34 @@
/* This is the "A small noncryptographic PRNG" by Bob Jenkins, later given the name JFS64.
http://burtleburtle.net/bob/rand/smallprng.html
"I wrote this PRNG. I place it in the public domain."
It's small, and good enough:
https://www.pcg-random.org/posts/bob-jenkins-small-prng-passes-practrand.html
*/
/* Adapted from https://github.com/nwc10/perl5/commit/16ff20f28225d92d24c7b0d7a7196c035640b27f */

/* Find best way to ROTL64 */
/* Copied from https://github.com/Perl/perl5/blob/d6b487cec2690eccc59f18bd6c3803ea06b3c9d6/hv_macro.h */
#if defined(_MSC_VER)
#include <stdlib.h> /* Microsoft put _rotl declaration in here */
#define ROTL64(x,r) _rotl64(x,r)
#else
/* gcc recognises this code and generates a rotate instruction for CPUs with one */
#define ROTL64(x,r) ( ( (MVMuint64)(x) << (r) ) | ( (MVMuint64)(x) >> ( 64 - (r) ) ) )
#endif

MVM_STATIC_INLINE MVMuint64 jfs64_generate_uint64(MVMuint64 *rand_state) {
MVMuint64 e = rand_state[0] - ROTL64(rand_state[1], 7);
rand_state[0] = rand_state[1] ^ ROTL64(rand_state[2], 13);
rand_state[1] = rand_state[2] + ROTL64(rand_state[3], 37);
rand_state[2] = rand_state[3] + e;
rand_state[3] = e + rand_state[0];
return rand_state[3];
}

MVM_STATIC_INLINE void jfs64_init(MVMuint64 *rand_state, MVMuint64 seed) {
rand_state[0] = 0xf1ea5eed;
rand_state[1] = rand_state[2] = rand_state[3] = seed;
for (int i = 0; i < 20; ++i) {
(void)jfs64_generate_uint64(rand_state);
}
}
2 changes: 1 addition & 1 deletion src/core/threadcontext.h
Expand Up @@ -278,7 +278,7 @@ struct MVMThreadContext {
MVMStrHashTable native_callback_cache;

/* Random number generator state. */
MVMuint64 rand_state[2];
MVMuint64 rand_state[4];

/* Temporary big integers for when we need to upgrade operands in order
* to perform an operation. */
Expand Down
11 changes: 5 additions & 6 deletions src/io/procops.c
@@ -1,7 +1,7 @@
#include "moar.h"
#include "platform/time.h"
#include "platform/fork.h"
#include "tinymt64.h"
#include "core/jfs64.h"
#include "bithacks.h"

/* concatenating with "" ensures that only literal strings are accepted as argument. */
Expand Down Expand Up @@ -1094,22 +1094,21 @@ MVMint64 MVM_proc_getppid(MVMThreadContext *tc) {

/* generates a random int64 */
MVMint64 MVM_proc_rand_i(MVMThreadContext *tc) {
MVMuint64 result = tinymt64_generate_uint64(tc->rand_state);
return *(MVMint64 *)&result;
return (MVMint64)jfs64_generate_uint64(tc->rand_state);
}

/* generates a number between 0 and 1 */
MVMnum64 MVM_proc_rand_n(MVMThreadContext *tc) {
return tinymt64_generate_double(tc->rand_state);
return ((jfs64_generate_uint64(tc->rand_state) >> 11) / (double)(1L << 53));
}

MVMnum64 MVM_proc_randscale_n(MVMThreadContext *tc, MVMnum64 scale) {
return tinymt64_generate_double(tc->rand_state) * scale;
return ((jfs64_generate_uint64(tc->rand_state) >> 11) / (double)(1L << 53)) * scale;
}

/* seed random number generator */
void MVM_proc_seed(MVMThreadContext *tc, MVMint64 seed) {
tinymt64_init(tc->rand_state, (MVMuint64)seed);
jfs64_init(tc->rand_state, (MVMuint64)seed);
}

/* gets the system time since the epoch in nanoseconds */
Expand Down
10 changes: 5 additions & 5 deletions src/math/bigintops.c
@@ -1,6 +1,6 @@
#include "moar.h"
#include "platform/random.h"
#include "tinymt64.h"
#include "core/jfs64.h"

#define MANTISSA_BITS_IN_DOUBLE 53
#define EXPONENT_SHIFT 52
Expand Down Expand Up @@ -1397,7 +1397,7 @@ MVMnum64 MVM_bigint_div_num(MVMThreadContext *tc, MVMObject *a, MVMObject *b) {
}

/* The below function is copied from libtommath and modified to use
* tinymt64 as the source of randomness. As of LTM v1.1.0, mp_rand()
* jfs64 as the source of randomness. As of LTM v1.1.0, mp_rand()
* uses sources of randomness that can't be seeded. Since we want to
* be able to do that, for now just copy and modify.
*/
Expand All @@ -1421,12 +1421,12 @@ mp_err MVM_mp_rand(MVMThreadContext *tc, mp_int *a, int digits)

/* TODO: We ensure that the highest digit is nonzero. Should this be removed? */
while ((a->dp[digits - 1] & MP_MASK) == 0u) {
a->dp[digits - 1] = tinymt64_generate_uint64(tc->rand_state);
a->dp[digits - 1] = jfs64_generate_uint64(tc->rand_state);
}

a->used = digits;
for (i = 0; i < digits; ++i) {
a->dp[i] = tinymt64_generate_uint64(tc->rand_state);
a->dp[i] = jfs64_generate_uint64(tc->rand_state);
a->dp[i] &= MP_MASK;
}

Expand Down Expand Up @@ -1465,7 +1465,7 @@ MVMObject * MVM_bigint_rand(MVMThreadContext *tc, MVMObject *type, MVMObject *b)

if (use_small_arithmetic) {
if (MP_GEN_RANDOM_MAX >= (unsigned long)abs(smallint_max)) {
mp_digit result_int = tinymt64_generate_uint64(tc->rand_state);
mp_digit result_int = jfs64_generate_uint64(tc->rand_state);
result_int = result_int % smallint_max;
if (have_to_negate)
result_int *= -1;
Expand Down

0 comments on commit 1550dc7

Please sign in to comment.