[Perl/perl5] 53ff92: Add support for an ${^RNG} hook, along with suppor...
[email protected] (Yves Orton via perl5-changes)
| Newsgroups | perl.perl5.changes |
|---|---|
| Message-ID | <Perl/perl5/push/refs/heads/yves/caret_rng_hook/[email protected]> |
Branch: refs/heads/yves/caret_rng_hook
Home: https://github.com/Perl/perl5
Commit: 53ff922de3131cc90c49e9dc51ea0f1d72eb57aa
https://github.com/Perl/perl5/commit/53ff922de3131cc90c49e9dc51ea0f1d72eb57aa
Author: Yves Orton <[email protected]>
Date: 2026-08-17 (Mon, 17 Aug 2026)
Changed paths:
M MANIFEST
M Makefile.SH
M Porting/Maintainers.pl
M Porting/cmpVERSION.pl
M Porting/config.sh
A dist/RNG/Changes
A dist/RNG/MANIFEST
A dist/RNG/Makefile.PL
A dist/RNG/README
A dist/RNG/RNG.xs
A dist/RNG/lib/RNG.pm
A dist/RNG/lib/RNG/PCG.pm
A dist/RNG/lib/RNG/SHA.pm
A dist/RNG/t/pcg.t
A dist/RNG/t/sha.t
M embed.fnc
M embed.h
M lib/.gitignore
A lib/RNG.pm
M pod/perldelta.pod
M pod/perldiag.pod
M pod/perlfunc.pod
M pod/perlvar.pod
M pp.c
M proto.h
M t/op/srand.t
M util.h
M win32/GNUmakefile
M win32/Makefile
Log Message:
-----------
Add support for an ${^RNG} hook, along with support PCG randomization
Historically the random number generator used by perl has evolved over
time, in the early days it was the system RNG, then later we rolled our
own version drand48 for cross platform stability. But these days
drand48 has a bunch of flaws so it would be nice to be able to use
something better.
However this is not so easy. Most code just calls rand() because it is
the easiest thing to do. Most people dont bother adding support for
their own hook, or burdening their user with providing an RNG,
especially as there is no standard for doing so. Some code maybe ends up
with support for an RNG hook, like List::Util did, but IMO such cases
are a rarity, and a proliferation of slightly different hooks for this
would not be helpful.
In theory one can override CORE::rand() and CORE::srand() before a
module is loaded, and thus change the RNG, but the reality is there is
no good way to overload srand()/rand() in another packages namespace.
(So when people say "just put your pet RNG on CPAN" it is kind of a cop
out, that RNG is likely to never really be useful as it just wont get
used by most code.)
At the same time we dont really want to change Perls internal code to
use something other than drand48(). There is lots of code that expects
that doing srand(1234) will produce test results that look a specific
way, so changing cores RNG would cause all kinds of unfortunate drama
through the ecosystem.
This patch takes a different approach: ${^RNG} is used as a hook for
rand() and srand(). If ${^RNG} contains an object then it uses the
objects rand_uv() and srand() methods to do its thing. If it
contains an unblessed subref then it calls it with no arguments for
rand() and with arguments for srand() (srand(undef) is defined to be
the same as srand()).
This is wired into the macro Drand01() which despite its name and
appearance is actually a pTHX style macro, but which actually hides the
fact by access what looks like a global var, but is actually an
interpreter var under threads, thus hiding that it does operate on aTHX
just not directly. This allows us to redirect so that modules like
List::Util will still respect the hook even though they bypass pp_rand()
for most of their random calls.
I thought about using ${^HOOKS}{RNG} instead of ${^RNG}, but for the
time I decided to just use ${^RNG} as it feels better to do
somethinglike:
local ${^RNG} = RNG::PCG->new();
than it does to do:
local ${^HOOKS}{RNG}
and it allows the rng internals to avoid the hash lookup. Although
currently it is not optimizing the ${^RNG} package var fetch, and the
var is not magic in any way so the ${^RNG} hook is not being stored in
an interpreter var so the current implementation could be sped up we
wished. IMO it is preferable to keep this as simple as possible.
As part of this patch I have added a new dist/RNG which contains XS code
to implement the two dimensional PCG-XSH-RR 64/128, which allows for 128
bit state with only 64 bit or 32 operations. This seems to be the state
of the art RNG these days.
I also implemented an RNG::SHA which uses SHA256 to produce the stream
of random values.
I chose to make RNG use a UV as its base currency, so rand() calls
${^RNG}->rand_uv() which returns a UV, which is then converted into
whatever the user requested. I did it this way so that any floating
point operations or conversion to floating point operations could be
performed by the C code. It feels like a more flexible foundation
than using a float.
Modules like List::Util which bind to Drand01() at the C level still
call the callback, so even without using List::Util's hook you can
override it just like any other perl code.
To unsubscribe from these emails, change your notification settings at https://github.com/Perl/perl5/settings/notifications