lexikos wrote: ↑25 Jun 2021, 04:06
And yet, the documentation never mentioned making the results deterministic, only improving the "quality/security" of the random numbers.
isnt that already implied by the concept of a pseudo-random number generator?
ive combed through my scripts for reseeding usages and ive used it once in an abandoned flappy bird clone, once in a monte carlo experiment i was trying out and 3 times just for debugging purposes(but not in production) as i was writing the script. obviously this code isnt uploaded anywhere(publicly accessible, at least that im aware), so u wouldnt have been able to come across it. we dont know how many other similar instances exist but ill grant u this much, reseeding probably isnt that popular a feature
The OP didn't share details, and the topic was about an inherent issue with this capability: it relies on shared global state.
seems to me he simply needed 3 separate instances of the PRNG engine(seeded with a particular number. perhaps the same number, perhaps a different one, doesnt matter). i imagine something equivalent to:
Code: Select all
std::mt19937_64 engine1;
std::mt19937_64 engine2;
std::mt19937_64 engine3;
this wouldnt have been possible with the old MT implementation, since there only ever was one instantiated engine, so what he wanted(using ahk builtin code) was impossible from the outset
Without RandomSeed(), no one will waste their time reading about it or considering using it, or sabotage their own efforts by choosing the seed poorly.
fair enough
The suggested solutions were:
- If you want the same sequences,
just precalculate them,
- ... or use C#.
ok, yeah the latter would work, i suppose
It would also be reasonably trivial to compile a C++ dll exposing some of the RNG functionality of STL, in which case different parts of the script can have different RNG state, or even separate algorithms.
as would this, the only downside being u now got to haul a DLL around
lexikos wrote: ↑25 Jun 2021, 04:12
Actually, jeeswg already translated it to ahk.
ive looked for it but wasnt able to find anything(and its not like i can ask him for it, for obvious reasons....), so i ported the v1 random to v2, so it can be used like the guy in the
proof of concept for a gaming application thread wanted to, ie to have multiple seedable generators:
Code: Select all
#Requires AutoHotkey v2.0-a137-f6f65742
Engine1 := RandomAHKv1(0)
Engine2 := RandomAHKv1(0)
str1 := ''
str2 := ''
Loop 5
{
str1 .= Engine1.Random() ','
str2 .= Engine2.Random() ','
}
MsgBox str1 '`n' str2
class RandomAHKv1 {
; check v1.1.33.09 source/docs for implementation details,
; requirements, permitted values, guarantees, etc..
__New(ui32Seed := unset) {
if !IsSet(ui32Seed)
ui32Seed := A_TickCount
try
this.Seed(ui32Seed)
catch as Err
throw %Type(Err)%(Err.Message, -1, Err.Extra)
}
Random(min := 0, max := 0x7FFFFFFF) {
if (min > max)
throw ValueError(A_ThisFunc ' failed. Min exceeds Max.', -1, min " > " max)
if (IsFloat(min) || IsFloat(max)) ; either is float
return (this.MT.genrand_real1() * (max - min)) + min
else
return Mod(this.MT.genrand_int32(), max - min + 1) + min
}
Seed(ui32Seed) {
if (!IsInteger(ui32Seed) || (ui32Seed < 0 || ui32Seed > 0xFFFFFFFF))
throw ValueError(A_ThisFunc ' failed due to invalid seed. A 32-bit unsigned int was expected.', -1, ui32Seed)
this.MT := MT19937(ui32Seed)
}
}
/*
C++ functions for MT19937, with initialization improved 2002/2/10.
Coded by Takuji Nishimura and Makoto Matsumoto.
This is a faster version by taking Shawn Cokus's optimization,
Matthe Bellew's simplification, Isaku Wada's real version.
Before using, initialize the state by using init_genrand(seed)
or init_by_array(init_key, key_length).
Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura,
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. The names of its contributors may not be used to endorse or promote
products derived from this software without specific prior written
permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Any feedback is very welcome.
http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html
email: m-mat@math.sci.hiroshima-u.ac.jp
*/
class MT19937 extends Array {
left := 0
next := 0
; zero-based array
__Item[i] {
get => super[i + 1]
set => super[i + 1] := value
}
; // initializes state[N] with a seed
; void init_genrand(unsigned long s)
; {
; int j;
;
; state[0]= s & 0xffffffffUL;
; for (j=1; j<N; j++) {
; /* See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier.
; * In the previous versions, MSBs of the seed affect
; * only MSBs of the array state[].
; * 2002/01/09 modified by Makoto Matsumoto */
; state[j] = (1812433253UL * (state[j-1] ^ (state[j-1] >> 30)) + j);
; state[j] &= 0xffffffffUL; // for >32 bit machines
; }
; left = 1;
; initf = 1;
; }
__New(ui32Seed) {
static N := 624 ; Period parameters
this.Length := N
this[0] := ui32Seed & 0xffffffff
; for (j=1; j<N; j++)
j := 1
while (j < N)
{
this[j] := (1812433253 * (this[j - 1] ^ (this[j - 1] >> 30)) + j)
this[j] &= 0xffffffff
j++
}
this.left := 1
}
; static void next_state(void)
; {
; unsigned long *p=state;
; int j;
;
; // if init_genrand() has not been called, a default initial seed is used
; if (initf==0)
; //init_genrand((unsigned long)time(NULL)); // get timer value
; init_genrand(GetTickCount()); // Avoiding the c-lib time functions reduces code size for AHK.
;
; left = N;
; next = state;
;
; for (j=N-M+1; --j; p++)
; *p = p[M] ^ TWIST(p[0], p[1]);
;
; for (j=M; --j; p++)
; *p = p[M-N] ^ TWIST(p[0], p[1]);
;
; *p = p[M-N] ^ TWIST(p[0], state[0]);
; }
next_state() {
static N := 624 ; Period parameters
static M := 397 ; Period parameters
p := 0
this.left := N
this.next := 0
; for (j=N-M+1; --j; p++)
j := N - M + 1
while (--j)
{
; *p = p[M] ^ TWIST(p[0], p[1]);
pM := this[p + M]
p0 := this[p]
p1 := this[p + 1]
this[p] := pM ^ TWIST(p0, p1)
p++
}
; for (j=M; --j; p++)
j := M
while (--j)
{
; *p = p[M-N] ^ TWIST(p[0], p[1]);
pMN := this[p + M - N]
p0 := this[p]
p1 := this[p + 1]
this[p] := pMN ^ TWIST(p0, p1)
p++
}
; *p = p[M-N] ^ TWIST(p[0], state[0]);
pMN := this[p + M - N]
p0 := this[p]
this[p] := pMN ^ TWIST(p0, this[0])
; #define MIXBITS(u,v) ( ((u) & UMASK) | ((v) & LMASK) )
MIXBITS(u, v) {
static UMASK := 0x80000000 ; // most significant w-r bits
static LMASK := 0x7fffffff ; // least significant r bits
return (u & UMASK) | (v & LMASK)
}
; #define TWIST(u,v) ((MIXBITS(u,v) >> 1) ^ ((v)&1UL ? MATRIX_A : 0UL))
TWIST(u, v) {
static MATRIX_A := 0x9908b0df ; // constant vector a
return (MIXBITS(u, v) >> 1) ^ ((v & 1) ? MATRIX_A : 0)
}
}
; // generates a random number on [0,0xffffffff]-interval
; unsigned long genrand_int32(void)
; {
; unsigned long y;
;
; if (--left == 0)
; next_state();
; y = *next++;
;
; // Tempering
; y ^= (y >> 11);
; y ^= (y << 7) & 0x9d2c5680UL;
; y ^= (y << 15) & 0xefc60000UL;
; y ^= (y >> 18);
;
; return y;
; }
genrand_int32() {
if (--this.left = 0)
this.next_state()
y := this[this.next++]
; // Tempering
y ^= (y >> 11)
y ^= (y << 7) & 0x9d2c5680
y ^= (y << 15) & 0xefc60000
y ^= (y >> 18)
return y
}
; // generates a random number on [0,1]-real-interval
; double genrand_real1(void)
; {
; ...
; return (double)y * (1.0/4294967295.0);
; // divided by 2^32-1
; }
genrand_real1() => this.genrand_int32() * (1.0/4294967295.0)
}
imo this hardly addresses anything. now u have to trust
me i implemented it correctly(and even i dont trust myself enough to believe that). or in the case of jeeswg's code -
him. or in the case of ahk's source -
you(and/or whoever wrote it originally back in the day). and if u used the STL - one or more microsoft guys(who i must assume must be at least somewhat knowledgeable about cryptography, why otherwise would they be charged with maintaining the
<random> header of the STL??).
now ask urself this, how many people who actually understand this shit have taken the time to audit my code? what about jeeswg's code? ahk's source? the STL? i dont have an answer for these questions, its probably impossible to tell anyways, but i think u see what im getting at...
... increases code size by around 7.5 KB.
... with RtlGenRandom "refunded" about 200 bytes
ok, i mean, in isolation 7500 bytes vs -200 bytes seems huge, but the exe is like 1meg. why does it matter if it ends up being 1meg or 1.007megs?
That's doubtful.
i beg to differ
Code: Select all
_f_return(std::uniform_real_distribution<double>(nmin, nmax)(g_rng));
...
// The first part below produces a 53-bit integer, and from that a value between
// 0.0 (inclusive) and 1.0 (exclusive) with the maximum precision for a double.
_f_return((((rand >> 11) / 9007199254740992.0) * (target_max - target_min)) + target_min);
What does this tell you about what the code does, that wouldn't be more clearly written in the documentation?
considering im no expert at this as previously mentioned, in either case i wont be able to interpret what im seeing, and yet the first one tells me i should have great deal of confidence(for reasons already discussed) im getting a number back
evenly distributed along the interval [a,b)
the other one tells me i should take at face value the code does what the comment says it does