Re-work PR 24105 to support threads and otherwise clean up - #24294
Re-work PR 24105 to support threads and otherwise clean up#24294tonycoz wants to merge 8 commits into
Conversation
since we may not be using drand48, just something that returns double (at least for now)
Some of this will be further changed: - moved the pcg64_random_t type to util.h so it's visible to intrpvar.h - changed the PL_RANDOM_STATE_TYPE to pcg64_random_t - changed the internal RNG to reference the new RNG and changed the macro names to something more generic (without "drand48") - added pcg64_random_t * parameters to the seed and RNG generation functions (and rename with _r) so we can make them thread safe and eliminate the global non-thread-safe random state - Needed to move the functions out of prng.h so porting/args_assert could find the function definitions and eliminate prng.h - re-define the original non-thread-safe functions as macro wrappers that pass in the state to the _r versions of the functions I plan to move all of the random stuff out of util.h/util.c into perlrand.h and random.c.
Perl supports larger floats, the existing code would drop bits of randomness on the floor, avoid that.
Make it easier to find the bits of perl that deal with random number generation and seeding.
I'm trying to figure out what this could mean. Can you clarify the double "have" in this sentence? Also is this PR merge-able? What else needs to be done? |
My typo, should be: "since they have the bits ..." In particular, you can build perl with it's internal floating point as
Probably in 5.45.0, but I'd like some review. |
Yeah I'd lean towards that too, we're quite late in the cycle for 5.44 now. |
|
I agree 100% this should target Perl v5.45, because we're too late into the release cycle. I will poke around with this code, see if I can get it to build and report back. Thanks @tonycoz |
|
I looked through this and it compiles and spits out appropriate PCG64 numbers. After some investigation it appears that most Perl installations use 8 byte NVs, which is essentially a double. Due to this, in order to produce less biased random floats, I think I have some minor white-space, and DEBUG clean-ups I'd like to land as part of this. Is there a way to submit a PR for this PR? Or how do I suggest changes? Otherwise I think this looks really solid. Thanks for the hard work @tonycoz |
This would lead to the bottom 11 bits of randomness being lost on builds with more precise NVs (I assume you want the shift back in or we won't get What does changing to -53 fix? I don't see how it change the bias of the result - in both cases the high-bits of the result will be the same. The only problem I can see with preserving those low bits for more precise NVs would be the slight difference in results, but I could see that preserving the bits reducing bias, ie. for
As mentioned in IRC, you could open a PR against my fork, or update your original PR. |
|
@tonycoz you're smart so I assume you know most of this, but I'm writing it all down for posterity for other people that have questions about generating random floats. PRNGs only generate integers. Thus if you have a 64bit PRNG it generates integers between 0 and 2^64 -1. Perl wants to give out floats instead of giving out integers. To convert a random number to a float the math appears simple: my $num = rand64();
my $float = $num / (2 ** 64 - 1);Due to the nature of doubles only being able to hold 53bits of mantissa (decimal values) this causes problems. The input has 2^64 potential values, but the output only has 2^53 potential values. This means that there are two input numbers that will generate the same output value. There is a small amount of bias because in those cases where there are duplicates there is a much higher chance of a particular random float coming out. The traditional method ("Generating uniform doubles") of generating random floats is to only use 53bits so that the input to output is 1:1. my $num = rand64();
$num >>= 11; # Use the most significant 53bits
my $float = $num / (2 ** 53 - 1); |
None of the examples on that page use The C example is: which has a different meaning to your expression, dividing by
With I suspect the issue is that for smaller input integers we get more possible output numbers for a given range of input, even if the [0, 1) range is still evenly distributed. And rounding might rear its ugly head too. Unfortunately we don't have a constant like |
|
You are correct, I was off by one in my examples above. I used the correct algorithm in my updated PR. |
If the goal is to get every available random bit to the user (an admirable goal) then we shouldn't be using floats. 53bits of randomness is probably suitable for 99% of use cases. In the situation where the user needs more, we should expose the raw underlying PRNG to return For the purposes of this PR I think that's beyond the scope. |
|
#24105 now includes the relevant changes. |
This is a expansion of #24105 which:
I've pointed the author of #24105 at this branch in the past.