1 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2 ;; UrForth level
1: self
-hosting
32-bit Forth compiler
3 ;; Copyright
(C
) 2020 Ketmar Dark
// Invisible Vector
5 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
11 absolutely non
-scientific stupid benchmark
:
13 bjprng
: 115,356,877 values
/second
14 bjprng
-3rots
: 115,109,543 values
/second
15 xorshift*
-64/32: 114,961,650 values
/second
16 pcg32
: 107,718,882 values
/second
17 pcg32ex
: 95,801,375 values
/second
19 as you can see
, 2-rot bjprng is the fastest one
, and it is quite good
.
20 pcg32
(with fixed stream
) is quite fast
, and it is good too
.
21 so i left only two of those in the kernel
, and moved others
to lib
.
23 include
!libs
/ext
/prngs
.f
24 to include rest of the generators
.
28 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
29 ;; generate
64-bit seed
(not cryptographically strong
!)
30 ;; also
, don
't call this repeatedly, it will produce bad seeds
31 : GEN-DSEED ( dlo dhi -- )
32 os:clock-monotonic os:clock-gettime u32hash swap u32hash xor os:get-pid xor u32hash ;; low seed
33 os:clock-monotonic os:clock-gettime u32hash swap u32hash xor ;; high seed
36 ;; useful to store 16-byte seeds
37 code: 4! ( a b c d addr -- )
53 code: 4@ ( addr -- a b c d )
69 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
70 ;; generate 32-bit random number, with first stream
71 ;; it uses smaller 64 bit state, and slightly faster
75 ;; state = oldstate*6364136223846793005UL+((42<<1)|1);
76 ;; u32 xorshifted = ((oldstate>>18)^oldstate)>>27;
77 ;; u32 rot = oldstate>>59;
78 ;; res = (xorshifted>>rot)|(xorshifted<<((-rot)&31));
79 code: PCG32-NEXT ( statelo statehi -- newstatelo newstatehi u32prv )
81 push EIP ;; it will be used in the code
82 sub esp,8 ;; and two temp vars
88 ld edx,[esp+12] ;; statehi
89 ld eax,[esp+16] ;; statelo
90 ld [esp+0],edx ;; tmpvar0
91 imul edx,edx,0x4c957f2d
92 imul ecx,eax,0x5851f42d
95 ld [esp+4],eax ;; tmpvar1
100 ld [esp+12],edx ;; statehi
101 ld edx,[esp+0] ;; tmpvar0
102 ld [esp+16],eax ;; statelo
103 ld eax,[esp+4] ;; tmpvar1
106 xor eax,[esp+4] ;; tmpvar1
107 xor edx,[esp+0] ;; tmpvar0
111 ld edx,[esp+0] ;; tmpvar0
112 ld eax,[esp+4] ;; tmpvar1
132 : PCG32-SEED-U64 ( dlo dhi -- statelo statehi )
133 0 0 pcg32-next drop d+ pcg32-next drop
137 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
138 ;; Bob Jenkins small PRNG -- http://burtleburtle.net/bob/rand/smallprng.html
147 code: BJ-NEXT ( a b c d -- a b c d u32prv )
154 ld edx,eax ;; save b, to use it later
162 ld ebx,eax ;; save c, to use it later
182 : BJ-SEED-U32 ( u -- a b c d )
183 ;; dup u32hash bj-seed-u64
184 ;; this is how BJ does it for 32-bit seeds
185 0xf1ea5eed swap dup dup ;; initial seed
186 20 for bj-next drop endfor ;; skip first 20 values, to perturb seed
189 ;; k8: this sux, don't use it
!
190 : BJ
-SEED
-U64
( du
-- a b c d
)
191 u32hash swap u32hash xor bj
-seed
-u32
195 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
196 ;; produce biased result
[0..range
)
197 ;; this is faster than division
, tho
198 ;; it multiplies range and prv
, and takes the high
32 bits of
64-bit result
199 ;; this
(seemingly
) performs worser than modulo on PRNGs with non
-32-bit range
200 ;; if you need biased ranged result
, and you are unsure
, use
"UMOD"
201 code: SMALL-BIASED-RANGE ( u32prv urange -- u1 )