add pseudo-random generator API

The MRG32k3a generator is fast when using unboxed floating-point
arithemtic. Since the Scheme compiler doesn't yet support that,
build MRG32k3a into the kernel and provide access via
`pseudo-random-generator` functions.

original commit: 3dd74679a6c2705440488d8c07c47852eb50a94b
This commit is contained in:
Matthew Flatt 2019-10-07 10:10:15 -06:00
parent 174c416f9e
commit 18d18b7ff6
16 changed files with 502 additions and 11 deletions

View File

@ -51,13 +51,13 @@ csrc=statics.c segment.c alloc.c symbol.c intern.c gcwrapper.c gc-oce.c gc-ocd.c
number.c schsig.c io.c new-io.c print.c fasl.c vfasl.c stats.c\
foreign.c prim.c prim5.c flushcache.c\
windows.c\
schlib.c thread.c expeditor.c scheme.c compress-io.c
schlib.c thread.c expeditor.c scheme.c compress-io.c random.c
cobj=statics.obj segment.obj alloc.obj symbol.obj intern.obj gcwrapper.obj gc-oce.obj gc-ocd.obj\
number.obj schsig.obj io.obj new-io.obj print.obj fasl.obj vfasl.obj stats.obj\
foreign.obj prim.obj prim5.obj flushcache.obj\
windows.obj\
schlib.obj thread.obj expeditor.obj scheme.obj compress-io.obj
schlib.obj thread.obj expeditor.obj scheme.obj compress-io.obj random.obj
hsrc=system.h types.h version.h globals.h externs.h compress-io.h segment.h gc.c thread.h sort.h itest.c

View File

@ -50,13 +50,13 @@ csrc=statics.c segment.c alloc.c symbol.c intern.c gcwrapper.c gc-oce.c gc-ocd.c
number.c schsig.c io.c new-io.c print.c fasl.c vfasl.c stats.c\
foreign.c prim.c prim5.c flushcache.c\
windows.c\
schlib.c thread.c expeditor.c scheme.c compress-io.c
schlib.c thread.c expeditor.c scheme.c compress-io.c random.c
cobj=statics.obj segment.obj alloc.obj symbol.obj intern.obj gcwrapper.obj gc-oce.obj gc-ocd.obj\
number.obj schsig.obj io.obj new-io.obj print.obj fasl.obj vfasl.obj stats.obj\
foreign.obj prim.obj prim5.obj flushcache.obj\
windows.obj\
schlib.obj thread.obj expeditor.obj scheme.obj compress-io.obj
schlib.obj thread.obj expeditor.obj scheme.obj compress-io.obj random.obj
hsrc=system.h types.h version.h globals.h externs.h compress-io.h segment.h gc.c thread.h sort.h itest.c

View File

@ -51,13 +51,13 @@ csrc=statics.c segment.c alloc.c symbol.c intern.c gcwrapper.c gc-oce.c gc-ocd.c
number.c schsig.c io.c new-io.c print.c fasl.c vfasl.c stats.c\
foreign.c prim.c prim5.c flushcache.c\
windows.c\
schlib.c thread.c expeditor.c scheme.c compress-io.c
schlib.c thread.c expeditor.c scheme.c compress-io.c random.c
cobj=statics.obj segment.obj alloc.obj symbol.obj intern.obj gcwrapper.obj gc-oce.obj gc-ocd.obj\
number.obj schsig.obj io.obj new-io.obj print.obj fasl.obj vfasl.obj stats.obj\
foreign.obj prim.obj prim5.obj flushcache.obj\
windows.obj\
schlib.obj thread.obj expeditor.obj scheme.obj compress-io.obj
schlib.obj thread.obj expeditor.obj scheme.obj compress-io.obj random.obj
hsrc=system.h types.h version.h globals.h externs.h compress-io.h segment.h gc.c thread.h sort.h itest.c

View File

@ -50,13 +50,13 @@ csrc=statics.c segment.c alloc.c symbol.c intern.c gcwrapper.c gc-oce.c gc-ocd.c
number.c schsig.c io.c new-io.c print.c fasl.c vfasl.c stats.c\
foreign.c prim.c prim5.c flushcache.c\
windows.c\
schlib.c thread.c expeditor.c scheme.c compress-io.c
schlib.c thread.c expeditor.c scheme.c compress-io.c random.c
cobj=statics.obj segment.obj alloc.obj symbol.obj intern.obj gcwrapper.obj gc-oce.obj gc-ocd.obj\
number.obj schsig.obj io.obj new-io.obj print.obj fasl.obj vfasl.obj stats.obj\
foreign.obj prim.obj prim5.obj flushcache.obj\
windows.obj\
schlib.obj thread.obj expeditor.obj scheme.obj compress-io.obj
schlib.obj thread.obj expeditor.obj scheme.obj compress-io.obj random.obj
hsrc=system.h types.h version.h globals.h externs.h compress-io.h segment.h gc.c thread.h sort.h itest.c

View File

@ -34,7 +34,7 @@ KernelLibLinkLibs=${zlibLib} ${LZ4Lib}
kernelsrc=statics.c segment.c alloc.c symbol.c intern.c gcwrapper.c gc-ocd.c gc-oce.c\
number.c schsig.c io.c new-io.c print.c fasl.c vfasl.c stats.c foreign.c prim.c prim5.c flushcache.c\
schlib.c thread.c expeditor.c scheme.c compress-io.c
schlib.c thread.c expeditor.c scheme.c compress-io.c random.c
kernelobj=${kernelsrc:%.c=%.$o} ${mdobj}

View File

@ -420,5 +420,12 @@ extern char *S_windows_getcwd(char *buffer, int maxlen);
extern void S_expeditor_init PROTO((void));
#endif /* FEATURE_EXPEDITOR */
/* random.c */
uptr S_random_state_next_integer PROTO((ptr s, uptr n));
double S_random_state_next_double PROTO((ptr s));
void S_random_state_init PROTO((ptr s, UINT x));
IBOOL S_random_state_check PROTO((double x10, double x11, double x12,
double x20, double x21, double x22));
/* statics.c */
extern void scheme_statics();

View File

@ -1596,6 +1596,10 @@ void S_prim5_init() {
Sforeign_symbol("(cs)s_float", (void *)s_float);
Sforeign_symbol("(cs)s_flrandom", (void *)s_flrandom);
Sforeign_symbol("(cs)s_fxrandom", (void *)s_fxrandom);
Sforeign_symbol("(cs)s_random_state_next_integer", (void *)S_random_state_next_integer);
Sforeign_symbol("(cs)s_random_state_next_double", (void *)S_random_state_next_double);
Sforeign_symbol("(cs)s_random_state_init", (void *)S_random_state_init);
Sforeign_symbol("(cs)s_random_state_check", (void *)S_random_state_check);
Sforeign_symbol("(cs)s_integer_length", (void *)S_integer_length);
Sforeign_symbol("(cs)s_big_first_bit_set", (void *)S_big_first_bit_set);
Sforeign_symbol("(cs)s_make_code", (void *)s_make_code);

188
c/random.c Normal file
View File

@ -0,0 +1,188 @@
#include "system.h"
/*
Based on
Implementation of SRFI-27 core generator in C for Racket.
dvanhorn@cs.uvm.edu
and
54-BIT (double) IMPLEMENTATION IN C OF THE "MRG32K3A" GENERATOR
===============================================================
Sebastian.Egner@philips.com, Mar-2002, in ANSI-C and Scheme 48 0.57
This code is a C-implementation of Pierre L'Ecuyer's MRG32k3a generator.
The code uses (double)-arithmetics, assuming that it covers the range
{-2^53..2^53-1} exactly (!). The code of the generator is based on the
L'Ecuyer's own implementation of the generator. Please refer to the
file 'mrg32k3a.scm' for more information about the method.
*/
/* Representation is arecord with 6 `double` fields: */
#define RANDSTATEX10(x) (((double*)&RECORDINSTIT(x, 0))[0])
#define RANDSTATEX11(x) (((double*)&RECORDINSTIT(x, 0))[1])
#define RANDSTATEX12(x) (((double*)&RECORDINSTIT(x, 0))[2])
#define RANDSTATEX20(x) (((double*)&RECORDINSTIT(x, 0))[3])
#define RANDSTATEX21(x) (((double*)&RECORDINSTIT(x, 0))[4])
#define RANDSTATEX22(x) (((double*)&RECORDINSTIT(x, 0))[5])
/* The Generator
=============
*/
/* moduli of the components */
#define Im1 0xffffff2f
#define Im2 0xffffa6bb
#define m1 4294967087.0
#define m2 4294944443.0
/* recursion coefficients of the components */
#define a12 1403580.0
#define a13n 810728.0
#define a21 527612.0
#define a23n 1370589.0
/* normalization factor 1/(m1 + 1) */
#define norm 2.328306549295728e-10
/* the actual generator */
static double mrg32k3a(ptr s) { /* (double), in {0..m1-1} */
double x10, x20, y;
iptr k10, k20;
/* component 1 */
x10 = a12*(RANDSTATEX11(s)) - a13n*(RANDSTATEX12(s));
k10 = (iptr)(x10 / m1);
x10 -= k10 * m1;
if (x10 < 0.0)
x10 += m1;
RANDSTATEX12(s) = RANDSTATEX11(s);
RANDSTATEX11(s) = RANDSTATEX10(s);
RANDSTATEX10(s) = x10;
/* component 2 */
x20 = a21*(RANDSTATEX20(s)) - a23n*(RANDSTATEX22(s));
k20 = (iptr)(x20 / m2);
x20 -= k20 * m2;
if (x20 < 0.0)
x20 += m2;
RANDSTATEX22(s) = RANDSTATEX21(s);
RANDSTATEX21(s) = RANDSTATEX20(s);
RANDSTATEX20(s) = x20;
/* combination of component */
y = x10 - x20;
if (y < 0.0)
y += m1;
return y;
}
/**************************************************/
/* The number `n` must be no more than 4294967087 */
uptr S_random_state_next_integer(ptr s, uptr n)
{
double x, q, qn, xq;
/* generate result in {0..n-1} using the rejection method */
q = (double)( (uptr)(m1 / (double)n) );
qn = q * n;
do {
x = mrg32k3a(s);
} while (x >= qn);
xq = x / q;
/* return result */
return (uptr)xq;
}
double S_random_state_next_double(ptr s)
{
double x;
x = mrg32k3a(s);
return (x + 1.0) * norm;
}
/**************************************************/
static UINT _random_m(UINT *_x)
{
UINT x, y;
x = *_x;
y = x & 0xFFFF;
x = (30903 * y) + (x >> 16);
*_x = x;
return y;
}
static int _random_n(UINT *_x, int n)
{
return ((_random_m(_x) << 16) + _random_m(_x)) % n;
}
static void sch_srand_half(UINT x, ptr s)
{
/* Due to integer overflow, this doesn't match the Scheme implementation!
We use "int" instead of "long" to make the overflow consistent
across platforms (since "long" is sometimes 64 bits). */
UINT z;
z = _random_n(&x, Im1-1);
RANDSTATEX10(s) = (double)(1 + (((UINT)RANDSTATEX10(s) + z) % (Im1 - 1)));
z = _random_n(&x, Im1);
RANDSTATEX11(s) = (double)(((UINT)RANDSTATEX11(s) + z) % Im1);
z = _random_n(&x, Im1);
RANDSTATEX12(s) = (double)(((UINT)RANDSTATEX12(s) + z) % Im1);
z = _random_n(&x, Im2-1);
RANDSTATEX20(s) = (double)(1 + (((UINT)RANDSTATEX20(s) + z) % (Im2 - 1)));
z = _random_n(&x, Im2);
RANDSTATEX21(s) = (double)(((UINT)RANDSTATEX21(s) + z) % Im2);
z = _random_n(&x, Im2);
RANDSTATEX22(s) = (double)(((UINT)RANDSTATEX22(s) + z) % Im2);
/* Due to the mismatch, maybe it's possible that we can hit a degeneracy?
Double-check, just in case... */
if (!RANDSTATEX10(s) && !RANDSTATEX11(s) && !RANDSTATEX12(s))
RANDSTATEX10(s) = 1;
if (!RANDSTATEX20(s) && !RANDSTATEX21(s) && !RANDSTATEX22(s))
RANDSTATEX20(s) = 1;
}
void S_random_state_init(ptr s, UINT x)
{
/* Initial values are from Sebastian Egner's implementation: */
RANDSTATEX10(s) = 1062452522.0;
RANDSTATEX11(s) = 2961816100.0;
RANDSTATEX12(s) = 342112271.0;
RANDSTATEX20(s) = 2854655037.0;
RANDSTATEX21(s) = 3321940838.0;
RANDSTATEX22(s) = 3542344109.0;
sch_srand_half(x & 0xFFFF, s);
sch_srand_half((x >> 16) & 0xFFFF, s);
}
/**************************************************/
IBOOL S_random_state_check(double x10, double x11, double x12,
double x20, double x21, double x22)
{
#define CHECK_RS_FIELD(x, top) if ((x < 0.0) || (x > ((top) - 1))) return 0;
CHECK_RS_FIELD(x10, Im1)
CHECK_RS_FIELD(x11, Im1)
CHECK_RS_FIELD(x12, Im1)
CHECK_RS_FIELD(x20, Im2)
CHECK_RS_FIELD(x21, Im2)
CHECK_RS_FIELD(x22, Im2)
if ((x10 == 0.0) && (x11 == 0.0) && (x12 == 0.0))
return 0;
if ((x20 == 0.0) && (x21 == 0.0) && (x22 == 0.0))
return 0;
return 1;
}

View File

@ -1419,6 +1419,86 @@ random seed to the argument.
(eqv? (random 1.0) r1))) ;=> #t
\endschemedisplay
%----------------------------------------------------------------------------
\entryheader
\formdef{make-pseudo-random-generator}{\categoryprocedure}{(make-pseudo-random-generator)}
\returns a fresh pseudo-random generator
\listlibraries
\endnoskipentryheader
\noindent
Creates a pseduo-random generator state for use with
\scheme{pseduo-random-generator-next!}. This generator use a more
modern algorithm than \scheme{random} and generates number sequences
that better approximate true randomness.
The initial state of the pseduo-random generator is based on the
current time, which is good enough for generating variability in most
programs but not good enough for security purposes.
%----------------------------------------------------------------------------
\entryheader
\formdef{pseudo-random-generator?}{\categoryprocedure}{(pseudo-random-generator? \var{val})}
\returns a boolean
\listlibraries
\endnoskipentryheader
\noindent
Checks whether \var{val} is a pseudo-random generator state.
%----------------------------------------------------------------------------
\entryheader
\formdef{pseudo-random-generator-next!}{\categoryprocedure}{(pseudo-random-generator-next! \var{prgen})}
\formdef{pseudo-random-generator-next!}{\categoryprocedure}{(pseudo-random-generator-next! \var{prgen} \var{below-int})}
\returns a pseduo-random number
\listlibraries
\endnoskipentryheader
\noindent
\var{prgen} must be a psuedo-random generator state. If \var{below-int} is
provided, it must be a positive, exact integer.
Steps a pseduo-random generator to produce a number. The result is an
inexact number between \scheme{0.0} (inclusive) and \scheme{1.0}
(exclusive) if \var{below-int} is not provided. If \scheme{below-int} is
provided, the result is an exact integer between \scheme{0} (inclusive)
and \scheme{below-int} (exclusive).
%----------------------------------------------------------------------------
\entryheader
\formdef{pseudo-random-generator-seed!}{\categoryprocedure}{(pseudo-random-generator-seed! \var{prgen} \var{seed-int})}
\returns unspecified
\listlibraries
\endnoskipentryheader
\noindent
\var{prgen} must be a psuedo-random generator state, and \var{seed-int} must
be a positive, exact integer.
Sets the state of a pseduo-random generator using only 31 or so bits
of \var{seed-int}. This procedure is useful for initializing the state
of a pseduo-random generator to one of a small number of known states
for triggering predicatble output, but it is not a good way to put a
generator into an unpredictable state.
%----------------------------------------------------------------------------
\entryheader
\formdef{pseudo-random-generator->vector}{\categoryprocedure}{(pseudo-random-generator->vector \var{prgen})}
\formdef{vector->pseudo-random-generator}{\categoryprocedure}{(vector->pseudo-random-generator \var{vec})}
\formdef{vector->pseudo-random-generator!}{\categoryprocedure}{(vector->pseudo-random-generator! \var{prgen} \var{vec})}
\returns unspecified
\listlibraries
\endnoskipentryheader
\noindent
\var{prgen} must be a psuedo-random generator state, and \var{vec} must
be a vector previously produced by \scheme{pseudo-random-generator->vector}.
\scheme{pseudo-random-generator->vector} converts the current state of
a pseduo-random generator to a vector of numbers, \scheme{vector->pseudo-random-generator}
creates a fresh pseudo-random generator with the same state, and
\scheme{vector->pseudo-random-generator!}
changes an existing pseudo-random generator to have the same state.
\section{Miscellaneous Numeric Operations\label{SECTNUMERICMISC}}

View File

@ -62,7 +62,7 @@ InstallLZ4Target=
# no changes should be needed below this point #
###############################################################################
Version=csv9.5.3.2
Version=csv9.5.3.3
Include=boot/$m
PetiteBoot=boot/$m/petite.boot
SchemeBoot=boot/$m/scheme.boot

View File

@ -2567,6 +2567,80 @@
#t)
)
(mat pseudo-random-generator
(pseudo-random-generator? (make-pseudo-random-generator))
(not (pseudo-random-generator? 10))
(not (pseudo-random-generator? (vector 1 2 3)))
(error? (pseudo-random-generator-next! 10))
(error? (pseudo-random-generator-next! (vector 1 2 3)))
(error? (pseudo-random-generator-next! (make-pseudo-random-generator) "apple"))
(error? (pseudo-random-generator-next! (make-pseudo-random-generator) 0))
(error? (pseudo-random-generator-next! (make-pseudo-random-generator) -10))
(error? (pseudo-random-generator-next! (make-pseudo-random-generator) (- (expt 2 100))))
(error? (pseudo-random-generator-next! (make-pseudo-random-generator) 10.0))
(error? (pseudo-random-generator-seed! 10 10))
(error? (pseudo-random-generator-seed! (vector 1 2 3) 10))
(error? (pseudo-random-generator-seed! (make-pseudo-random-generator) 10.0))
(error? (pseudo-random-generator-seed! (make-pseudo-random-generator) 0))
(error? (pseudo-random-generator-seed! (make-pseudo-random-generator) -1))
(error? (pseudo-random-generator->vector 0))
(error? (vector->pseudo-random-generator 0))
(error? (vector->pseudo-random-generator (vector 1 2 3 4 5)))
(error? (vector->pseudo-random-generator (vector 1.0 2 3 4 5 6)))
(error? (vector->pseudo-random-generator (vector 1 #f 3 4 5 6)))
(error? (vector->pseudo-random-generator (vector 0 0 0 0 0 0))) ; would be degenerate state
(error? (vector->pseudo-random-generator! 0 (vector 1 2 3 4 5)))
(error? (vector->pseudo-random-generator! (make-pseudo-random-generator) 0))
(error? (vector->pseudo-random-generator! (make-pseudo-random-generator) (vector 0 0 0 0 0 0)))
(begin
(define prgen (make-pseudo-random-generator))
(define init-pregen-vec (pseudo-random-generator->vector prgen))
(vector? init-pregen-vec))
(equal? init-pregen-vec (pseudo-random-generator->vector prgen))
(begin
(define first-prgen-number (pseudo-random-generator-next! prgen))
(inexact? first-prgen-number))
(and (<= 0.0 first-prgen-number)
(< first-prgen-number 1.0))
(not (equal? init-pregen-vec (pseudo-random-generator->vector prgen)))
(= first-prgen-number
(pseudo-random-generator-next!
(vector->pseudo-random-generator init-pregen-vec)))
(let loop ([i 10000])
(or (zero? i)
(let ([n (pseudo-random-generator-next! prgen i)])
(and (exact? n)
(integer? n)
(< -1 n i)
(loop (sub1 i))))))
(equal? (void) (vector->pseudo-random-generator! prgen init-pregen-vec))
(= first-prgen-number (pseudo-random-generator-next! prgen))
(equal? (void) (pseudo-random-generator-seed! prgen 45))
(= 0.970453319804345 (pseudo-random-generator-next! prgen))
(= 0.41754101818626094 (pseudo-random-generator-next! prgen))
(= 0.13061439482676662 (pseudo-random-generator-next! prgen))
(let ([hits (make-vector 10)])
(let loop ([i 1000])
(unless (zero? i)
(let* ([n (pseudo-random-generator-next! prgen (expt 10 1000))]
[k (quotient n (expt 10 999))])
(vector-set! hits k (add1 (vector-ref hits k)))
(loop (sub1 i)))))
;; We expect about 100 hits in each bin. Having less than 50 or
;; more than 150 should be so etxremely unlikely that we can rely on
;; it not happning:
(let loop ([i (vector-length hits)])
(or (= i 0)
(and (< 50 (vector-ref hits (sub1 i)) 150)
(loop (sub1 i))))))
)
(mat inexact
(error? (inexact))
(error? (inexact 1 2))

View File

@ -424,6 +424,7 @@
[(pathname) "a" 'a #f]
[(pfixnum) 1 0 #f]
[(phantom-bytevector) *phantom-bytevector '#vu8(0) #f]
[(pseudo-random-generator) *pseudo-random-generator #f]
[(port) (current-input-port) 0 #f]
[(procedure) values 0 #f]
[(ptr) 1.0+2.0i]

View File

@ -1308,6 +1308,27 @@ primvars.mo:Expected error in mat trace-output-port: "trace-output-port: #<input
5_3.mo:Expected error in mat random-seed: "random-seed: invalid argument 0".
5_3.mo:Expected error in mat random-seed: "random-seed: invalid argument -1".
5_3.mo:Expected error in mat random-seed: "random-seed: invalid argument <int>".
5_3.mo:Expected error in mat pseudo-random-generator: "pseudo-random-generator-next!: not a pseudo-random generator 10".
5_3.mo:Expected error in mat pseudo-random-generator: "pseudo-random-generator-next!: not a pseudo-random generator #(1 2 3)".
5_3.mo:Expected error in mat pseudo-random-generator: "pseudo-random-generator-next!: not a positive exact integer "apple"".
5_3.mo:Expected error in mat pseudo-random-generator: "pseudo-random-generator-next!: not a positive exact integer 0".
5_3.mo:Expected error in mat pseudo-random-generator: "pseudo-random-generator-next!: not a positive exact integer -10".
5_3.mo:Expected error in mat pseudo-random-generator: "pseudo-random-generator-next!: not a positive exact integer -1267650600228229401496703205376".
5_3.mo:Expected error in mat pseudo-random-generator: "pseudo-random-generator-next!: not a positive exact integer 10.0".
5_3.mo:Expected error in mat pseudo-random-generator: "pseudo-random-generator-seed!: not a pseudo-random generator 10".
5_3.mo:Expected error in mat pseudo-random-generator: "pseudo-random-generator-seed!: not a pseudo-random generator #(1 2 3)".
5_3.mo:Expected error in mat pseudo-random-generator: "pseudo-random-generator-seed!: not a positive exact integer 10.0".
5_3.mo:Expected error in mat pseudo-random-generator: "pseudo-random-generator-seed!: not a positive exact integer 0".
5_3.mo:Expected error in mat pseudo-random-generator: "pseudo-random-generator-seed!: not a positive exact integer -1".
5_3.mo:Expected error in mat pseudo-random-generator: "pseudo-random-generator->vector: not a pseudo-random generator 0".
5_3.mo:Expected error in mat pseudo-random-generator: "vector->pseudo-random-generator: not a valid pseudo-random generator state vector 0".
5_3.mo:Expected error in mat pseudo-random-generator: "vector->pseudo-random-generator: not a valid pseudo-random generator state vector #(1 2 3 4 5)".
5_3.mo:Expected error in mat pseudo-random-generator: "vector->pseudo-random-generator: not a valid pseudo-random generator state vector #(1.0 2 3 4 5 6)".
5_3.mo:Expected error in mat pseudo-random-generator: "exact?: #f is not a number".
5_3.mo:Expected error in mat pseudo-random-generator: "vector->pseudo-random-generator: not a valid pseudo-random generator state vector #(0 0 0 0 0 0)".
5_3.mo:Expected error in mat pseudo-random-generator: "vector->pseudo-random-generator!: not a pseudo-random generator 0".
5_3.mo:Expected error in mat pseudo-random-generator: "vector->pseudo-random-generator!: not a valid pseudo-random generator state vector 0".
5_3.mo:Expected error in mat pseudo-random-generator: "vector->pseudo-random-generator!: not a valid pseudo-random generator state vector #(0 0 0 0 0 0)".
5_3.mo:Expected error in mat inexact: "incorrect argument count in call (inexact)".
5_3.mo:Expected error in mat inexact: "incorrect argument count in call (inexact 1 2)".
5_3.mo:Expected error in mat inexact: "inexact: a is not a number".

109
s/5_3.ss
View File

@ -2597,6 +2597,115 @@
[else (nonexact-integer-error '$quotient-remainder x)])]
[else (nonexact-integer-error '$quotient-remainder y)])))
(let ()
(define-record pseudo-random-generator
((mutable double x10)
(mutable double x11)
(mutable double x12)
(mutable double x20)
(mutable double x21)
(mutable double x22))
()
((constructor create-pseudo-random-generator)
(predicate is-pseudo-random-generator?)))
(set! pseudo-random-generator?
(lambda (x) (is-pseudo-random-generator? x)))
(let ([init! (foreign-procedure "(cs)s_random_state_init" (scheme-object unsigned) void)])
(set! make-pseudo-random-generator
(lambda ()
(let ([s (create-pseudo-random-generator 0.0 0.0 0.0 0.0 0.0 0.0)]
[t (current-time 'time-utc)])
(init! s (bitwise-and (+ (time-second t) (time-nanosecond t))
#xFFFFFFFF))
s)))
(set-who! pseudo-random-generator-seed!
(lambda (s n)
(unless (is-pseudo-random-generator? s) ($oops who "not a pseudo-random generator ~s" s))
(unless (or (and (fixnum? n) (fxpositive? n))
(and (bignum? n) ($bigpositive? n)))
($oops who "not a positive exact integer ~s" n))
(init! s (bitwise-and n #xFFFFFFFF)))))
(set-who! pseudo-random-generator-next!
(let ([random-double (foreign-procedure "(cs)s_random_state_next_double"
(scheme-object) double)]
[random-int (foreign-procedure "(cs)s_random_state_next_integer"
(scheme-object uptr) uptr)])
(case-lambda
[(s)
(unless (is-pseudo-random-generator? s) ($oops who "not a pseudo-random generator ~s" s))
(random-double s)]
[(s x)
(define (random-integer s x)
(modulo (let loop ([bits (integer-length x)])
(cond
[(<= bits 0) 0]
[else (bitwise-ior (bitwise-arithmetic-shift-left (loop (- bits 24)) 24)
(random-int s #xFFFFFF))]))
x))
(unless (is-pseudo-random-generator? s) ($oops who "not a pseudo-random generator ~s" s))
(cond
[(fixnum? x)
(unless (fxpositive? x) ($oops who "not a positive exact integer ~s" x))
(meta-cond
[(fixnum? 4294967087)
(if (fx< x 4294967087)
(random-int s x)
(random-integer s x))]
[else
(random-int s x)])]
[(bignum? x)
(unless ($bigpositive? x) ($oops who "not a positive exact integer ~s" x))
(random-integer s x)]
[else
($oops who "not a positive exact integer ~s" x)])])))
(set-who! pseudo-random-generator->vector
(lambda (s)
(unless (is-pseudo-random-generator? s) ($oops who "not a pseudo-random generator ~s" s))
(vector (inexact->exact (pseudo-random-generator-x10 s))
(inexact->exact (pseudo-random-generator-x11 s))
(inexact->exact (pseudo-random-generator-x12 s))
(inexact->exact (pseudo-random-generator-x20 s))
(inexact->exact (pseudo-random-generator-x21 s))
(inexact->exact (pseudo-random-generator-x22 s)))))
(let ([vector->prgen
(let ([ok? (foreign-procedure "(cs)s_random_state_check" (double double double double double double) boolean)])
(lambda (who s v)
(define (bad-vector)
($oops who "not a valid pseudo-random generator state vector ~s" v))
(define (int->double i)
(unless (and (exact? i) (integer? i)) (bad-vector))
(exact->inexact i))
(unless (and (vector? v) (= 6 (vector-length v))) (bad-vector))
(let ([x10 (int->double (vector-ref v 0))]
[x11 (int->double (vector-ref v 1))]
[x12 (int->double (vector-ref v 2))]
[x20 (int->double (vector-ref v 3))]
[x21 (int->double (vector-ref v 4))]
[x22 (int->double (vector-ref v 5))])
(unless (ok? x10 x11 x12 x20 x21 x22) (bad-vector))
(cond
[s
(set-pseudo-random-generator-x10! s x10)
(set-pseudo-random-generator-x11! s x11)
(set-pseudo-random-generator-x12! s x12)
(set-pseudo-random-generator-x20! s x20)
(set-pseudo-random-generator-x21! s x21)
(set-pseudo-random-generator-x22! s x22)]
[else
(create-pseudo-random-generator x10 x11 x12 x20 x21 x22)]))))])
(set-who! vector->pseudo-random-generator
(lambda (vec) (vector->prgen who #f vec)))
(set-who! vector->pseudo-random-generator!
(lambda (s vec)
(unless (is-pseudo-random-generator? s) ($oops who "not a pseudo-random generator ~s" s))
(vector->prgen who s vec)))))
(set! random
(let ([fxrandom (foreign-procedure "(cs)s_fxrandom"
(scheme-object) scheme-object)]

View File

@ -328,7 +328,7 @@
[(_ foo e1 e2) e1] ...
[(_ bar e1 e2) e2]))))])))
(define-constant scheme-version #x09050302)
(define-constant scheme-version #x09050303)
(define-syntax define-machine-types
(lambda (x)

View File

@ -1468,6 +1468,7 @@
(make-output-port [sig [(procedure string) -> (textual-output-port)]] [flags alloc])
(make-parameter [sig [(ptr) (ptr procedure) -> (procedure)]] [flags true cp02 cp03])
(make-phantom-bytevector [sig [(uptr) -> (phantom-bytevector)]] [flags true])
(make-pseudo-random-generator [sig [() -> (pseudo-random-generator)]] [flags true])
(make-record-type [sig [(sub-ptr sub-list) (maybe-rtd sub-ptr sub-list) -> (rtd)]] [flags pure alloc cp02])
(make-source-condition [sig [(ptr) -> (condition)]] [flags pure unrestricted mifoldable discard])
(make-source-file-descriptor [sig [(string binary-input-port) (string binary-input-port ptr) (string binary-input-port ptr ptr) -> (sfd)]] [flags true])
@ -1565,6 +1566,10 @@
(putprop [sig [(symbol ptr ptr) -> (void)]] [flags true safeongoodargs])
(putenv [sig [(string string) -> (void)]] [flags true])
(profile-query-weight [sig [(ptr) -> (maybe-flonum)]] [flags unrestricted discard])
(pseudo-random-generator->vector [sig [(pseudo-random-generator) -> (vector)]] [flags])
(pseudo-random-generator-seed! [sig [(pseudo-random-generator sub-number) -> (void)]] [flags])
(pseudo-random-generator-next! [sig [(pseudo-random-generator) -> (number)] [(sub-number pseudo-random-generator) -> (number)]] [flags])
(pseudo-random-generator? [sig [(ptr) -> (boolean)]] [flags pure unrestricted mifoldable discard])
(random [sig [(sub-number) -> (number)]] [flags alloc])
(ratnum? [sig [(ptr) -> (boolean)]] [flags pure unrestricted mifoldable discard])
(read-token [sig [() (textual-input-port) (textual-input-port sfd) -> (symbol ptr maybe-uint maybe-uint)]] [flags])
@ -1733,6 +1738,8 @@
(vector-cas! [sig [(vector sub-index ptr ptr) -> (boolean)]] [flags])
(vector-copy [sig [(vector) -> (vector)]] [flags alloc safeongoodargs])
(vector->immutable-vector [sig [(vector) -> (vector)]] [flags alloc safeongoodargs])
(vector->pseudo-random-generator [sig [(vector) -> (pseudo-random-generator)]] [flags])
(vector->pseudo-random-generator! [sig [(pseudo-random-generator vector) -> (void)]] [flags])
(vector-set-fixnum! [sig [(vector sub-index fixnum) -> (void)]] [flags true])
(virtual-register [sig [(sub-index) -> (ptr)]] [flags discard])
(virtual-register-count [sig [() -> (length)]] [flags pure unrestricted true cp02])