in reply to Re: Legacy code uses "srand()" .. how to avoid losing entropy?
in thread Legacy code uses "srand()" .. how to avoid losing entropy?

What the code specifically does is to “hash” an identification string into an integer, $n, which is never zero, then it calls srand($n).   This does produce a repeatable sequence.

My objection, of course, is that once you have re-seeded the built-in PRNG, you can’t return it to its previous seed value ... because, AFAIK, you can’t find out what it is.   Since the PRNG is being constantly re-seeded, the values that it is producing over time are not nearly as random as they need to be throughout the rest of the program.   This is producing a bias problem that is quite serious.

I guess my real question becomes, “is there a way that I can capture what is the present value of the internal seed, so that, after running the code that requires re-seeding to occur, I can restore the original value and thus preserve randomness?”

Another “tom twiddy” strategy might be to capture a random number, multiply to make a large integer (because it seems that the seed is an integer?), and then, upon completion of the repeatable-sequence code, srand() again with that value.   The sequence would still show the unmistakable statistical influences caused by the fact that re-seeding is taking place, but at least it would be much more “randomized” than it is right now.   Anyone care to weigh-in on that “Plan B?”

I am definitely going to “sunset” this way of doing things, but unfortunately that means changes to a rather massive, heavily-mirrored database, with consequent down-time that just can’t be considered right now.

Replies are listed 'Best First'.
Re^3: Legacy code uses "srand()" .. how to avoid losing entropy?
by anonymized user 468275 (Curate) on May 03, 2011 at 12:58 UTC
    That value is going to be hidden away in the underlying C or C++ installation by which your Perl was compiled at Perl-installation time. It isn't going to be easy to break into. It would be easier to say globally replace srand with a call to a wrapper function capsrand that captures it on calling before passing it to the real srand. e.g.:
    package CapSrand; sub new { bless { LOG => [], LEN => 10 }; } sub capsrand { my $self = shift; -* $self -> { PARM } = shift; $self -> capture; srand( $self -> { PARM } ); } sub capture { # note: LIFO queue my $self = shift; unshift @{ $self -> { LOG } }, $self -> { PARM }; $#{ $self -> { LOG } } >= $self -> { LEN } and $#{ $self -> { LOG } } = $self -> { LEN } - 1; } sub latest { my $self = shift; $self -> { LOG }[ 0 ] or undef(); } 1;
    Update: to address the question of improving randomness by priming the seed, the usual way is to extract the most random behaving digits out of a time representation (usually near but not at the end of the sequence).

    For example if the time representation (e.g. in fractions of years since epoch) is 31.57065428547826, then the temptation is to take the last few digits for a seed, whereas these are more likely to repeat than say the 8th thru 11th digits of the 14 after the "." owing to the rounding enforced by the O/S to say 1/1000 of a second, which screws the randomness of just the last three digits.

    One world, one people