in reply to is rand random enough to simulate dice rolls?

G'day Discipulus,

About a decade ago, I wrote dice rolling code using almost exactly the same code as you show here. It was for use with a table-top RPG; it handled die with any number of sides.

Over the years, I added lots of features around the code (mostly ever-more fancy Tk interfaces) but the core dice-rolling code was unchanged.

I've used this code with Perl versions ranging from 5.12 to 5.32. Perl installations have included Perlbrew, Strawberry Perl and ActivePerl. Platforms have included WinXP & Win10 (both +/- Cygwin) and various Mac OS X/macOS versions.

I don't possess any data on checking averages; although, at different times, I have successfully run similar tests to those you show. In real-world usage, I've never noticed any problems, such as persistently getting high or low rolls; I appreciate that's not really any sort of strict or scientific check.

If your intended usage is similar to mine — you only said "a little project just to clean my rusty hands" — then I'd say rand() is sufficient. If your use case differs, then I see a plethora of advice in other posts that might be more appropriate.

"... can I expect the same result on every platform? and for every perl version around the world?"

Given the number of platforms that can run Perl, and the number of Perl versions around, I doubt you'd ever get a completely definitive answer to that question. However, you could ask people to supply the output from the same code and at least get a representative answer. Here's some suggested code (which I think should run on any version of Perl5):

$ perl -e ' my $iters = 100_000; my $runs = 6; for my $sides (qw{1 2 3 4 6 8 10 20 100}) { printf "%-5s", "D$sides:"; for (1 .. $runs) { my $tot = 0; for (1 .. $iters) { $tot += int(rand $sides)+1; } print " ", $tot/$iters; } print "\n"; } '

As a one-liner, for a quick copy-and-paste (although, given use of the [download] link, copying the original might be just as quick):

perl -e 'my $iters = 100_000; my $runs = 6; for my $sides (qw{1 2 3 4 +6 8 10 20 100}) { printf "%-5s", "D$sides:"; for (1 .. $runs) { my $t +ot = 0; for (1 .. $iters) { $tot += int(rand $sides)+1; } print " ", +$tot/$iters; } print "\n"; } '

Here's sample output using my Win10/Cygwin/Perlbrew/Perl 5.32.0:

D1: 1 1 1 1 1 1 D2: 1.49943 1.5049 1.49996 1.49833 1.50001 1.50155 D3: 2.00469 1.99941 1.99753 1.99721 1.99762 2.00254 D4: 2.49589 2.49891 2.49487 2.50727 2.49977 2.49472 D6: 3.49716 3.49463 3.49886 3.50365 3.49936 3.50401 D8: 4.50082 4.51098 4.50972 4.49368 4.50158 4.5112 D10: 5.4949 5.48275 5.50242 5.50131 5.49563 5.51278 D20: 10.47763 10.47848 10.50873 10.48685 10.48474 10.51209 D100: 50.36542 50.49534 50.49152 50.40469 50.53791 50.34646

If you could get a few people to post results for a variety of platforms, installations and Perl versions that they might have available, you may get something approaching a reasonable answer to your "every platform ... every version" question.

And, just in case those three nested loops resulting in 5,400,000 calls to rand() is of concern, the whole run only took about one second on my computer. I have a reasonably high-end rig: YMMV but hopefully not too much; I don't think this will tie up anyone's computer for hours.

— Ken

Replies are listed 'Best First'.
Re^2: is rand random enough to simulate dice rolls?
by shmem (Chancellor) on Jan 04, 2021 at 06:59 UTC
    If you could get a few people to post results for a variety of platforms, installations and Perl versions that they might have available, you may get something approaching a reasonable answer to your "every platform ... every version" question.

    Well, here's an old platform and an old version ;-)

    canis [shmem] /home/shmem > time perl -e 'my $iters = 100_000; my $run +s = 6; for my $sides (qw{1 2 3 4 6 8 10 20 100}) { printf "%-5s", "D$ +sides:"; for (1 .. $runs) { my $tot = 0; for (1 .. $iters) { $tot += +int(rand $sides)+1; } print " ", $tot/$iters; } print "\n"; } ' D1: 1 1 1 1 1 1 D2: 1.5017 1.50273 1.49927 1.50004 1.50069 1.50234 D3: 2.00005 2.0013 1.99667 2.00228 2.00141 2.0018 D4: 2.49651 2.49254 2.50251 2.5008 2.49389 2.50032 D6: 3.4947 3.49803 3.4938 3.50231 3.50249 3.49613 D8: 4.50561 4.51195 4.51012 4.50395 4.4961 4.50096 D10: 5.52471 5.50722 5.50845 5.4933 5.4983 5.49319 D20: 10.51722 10.48846 10.52023 10.50762 10.48594 10.52206 D100: 50.43492 50.46292 50.4675 50.66063 50.35462 50.46591 293.510u 0.450s 4:54.97 99.6% 0+1599k 4+7io 1pf+0w canis [shmem] /home/shmem > uname -a SunOS canis 4.1.4 5 sun4m canis [shmem] /home/shmem > perl -v This is perl, version 5.004 Copyright 1987-1997, Larry Wall Perl may be copied only under the terms of either the Artistic License + or the GNU General Public License, which may be found in the Perl 5.0 source +kit.

    SPARCstation voyager, cpu = SUNW,S240. Sorry, no PDP-11 available, and the Atari is out of order.

    Update: looks like perl4 is significantly slower. But the numbers look right.

    canis [shmem] /home/shmem > time perl4 -e '$iters = 100_000; $runs = 6 +; for $sides (1,2,3,4,6,8,10,20,100) { printf "%-5s", "D$sides:"; for + (1 .. $runs) { $tot = 0; for (1 .. $iters) { $tot += int(rand $sides +)+1; } print " ", $tot/$iters; } print "\n"; }' D1: 1 1 1 1 1 1 D2: 1.4976199999999999513 1.4995000000000000551 1.500839999999999951 +9 1.5009200000000000319 1.4983500000000000707 1.4992000000000000881 D3: 1.9988500000000000156 2.0010099999999999554 1.997360000000000024 +3 1.9947699999999999321 2.0022500000000000853 1.9987600000000000922 D4: 2.4961099999999998289 2.5017000000000000348 2.501459999999999794 +8 2.4986999999999999211 2.4970900000000000318 2.5005099999999997884 D6: 3.50016000000000016 3.4905300000000001326 3.5027200000000000557 +3.4986999999999999211 3.4940500000000001002 3.4981499999999998707 D8: 4.5008200000000000429 4.4963499999999996248 4.499399999999999622 + 4.505130000000000301 4.500880000000000436 4.4966600000000003234 D10: 5.5046299999999996899 5.4901400000000002422 5.493229999999999613 +2 5.4982899999999998997 5.4878000000000000114 5.481379999999999697 D20: 10.478590000000000515 10.511730000000000018 10.48712000000000088 +6 10.511749999999999261 10.520690000000000097 10.513320000000000221 D100: 50.332399999999999807 50.534730000000003258 50.68713999999999941 +8 50.558239999999997849 50.449489999999997281 50.479340000000000543 473.690u 154.350s 26:25.22 39.6% 0+4164k 0+7io 39159pf+0w canis [shmem] /home/shmem > perl4 -v This is perl, version 4.0 $RCSfile: perl.c,v $$Revision: 4.0.1.4 $$Date: 91/06/10 01:23:07 $ Patch level: 10 Copyright (c) 1989, 1990, 1991, Larry Wall Perl may be copied only under the terms of either the Artistic License + or the GNU General Public License, which may be found in the Perl 4.0 source +kit.
    perl -le'print map{pack c,($-++?1:13)+ord}split//,ESEL'
Re^2: is rand random enough to simulate dice rolls?
by GrandFather (Saint) on Jan 04, 2021 at 00:34 UTC
    D1: 1 1 1 1 1 1 D2: 1.50264 1.50089 1.49874 1.4986 1.49999 1.50096 D3: 1.99666 2.00076 1.99974 2.00305 1.99855 2.00081 D4: 2.49717 2.50553 2.49876 2.50477 2.50204 2.50298 D6: 3.49901 3.50656 3.49592 3.49852 3.51048 3.49704 D8: 4.49035 4.50043 4.48853 4.49734 4.49567 4.49206 D10: 5.50564 5.48776 5.50685 5.50959 5.50021 5.50671 D20: 10.50074 10.48721 10.49889 10.50993 10.48554 10.52566 D100: 50.45232 50.43541 50.54345 50.61081 50.64355 50.45597 Perl v5.30.1 MSWin32n

    I added:

    print "Perl $^V\ $^On";

    As pointed out by the sharp eyed shmem, kcott and NetWallah, I fat fingered the \ for the \n. Thanks guys. I've leaving the error version to keep myself humble.

    Optimising for fewest key strokes only makes sense transmitting to Pluto or beyond
      I added:
      print "Perl $^V\ $^On";

      Move that backslash a bit to the right. ;)

      perl -le'print map{pack c,($-++?1:13)+ord}split//,ESEL'

        More like 32 bits to the right, but yes. Must be something to do with the holiday spirit (see end).

        Optimising for fewest key strokes only makes sense transmitting to Pluto or beyond
Re^2: is rand random enough to simulate dice rolls?
by Discipulus (Canon) on Jan 04, 2021 at 08:40 UTC
    Fantastic kcott,

    Here the win32 version of the oneliner, with added info about perl and OS:

    perl -e "my $iters = 100_000; my $runs = 6; for my $sides (qw{1 2 3 4 +6 8 10 20 100}) { printf '%-5s', qq(D$sides:); for (1 ..$runs) { my $ +tot = 0; for (1 .. $iters) { $tot += int(rand $sides)+1; } print ' ', + $tot/$iters; } print qq(\n); } print qq(Perl $^V $^O\n)"

    And here are mine test results, all tests done in win10 and various strawberry protable:

    L*

    There are no rules, there are no thumbs..
    Reinvent the wheel, then learn The Wheel; may be one day you reinvent one of THE WHEELS.
      I saw this post while looking up old PDL nodes, and you mentioned PDL there. PDL as of 2.062 uses a "better" (and thread-safe, for potential massive performance gainz) pseudo-random number generator, xoroshiro256plus (see link for thorough statistical analysis of it and competing algorithms) rather than the often-weak and usually non-thread-safe system rand() that Perl uses.
      And here are mine test results, all tests done in win10 and various strawberry protable:

      And your conclusion is? It looks to me like all those perls are pretty well behaved, including my old ones (see above).

      perl -le'print map{pack c,($-++?1:13)+ord}split//,ESEL'
        Hello shmem,

        > And your conclusion is? It looks to me like all those perls are pretty well behaved, including my old ones

        Yes it seems so. My conclusion was in Re^2: is rand random enough to simulate dice rolls?: as haukex and other said is unwise to break a test for something related to a core function which might have problems in preistoric installations. A big warning, as above, is more than nothing in case of test failure.

        L*

        There are no rules, there are no thumbs..
        Reinvent the wheel, then learn The Wheel; may be one day you reinvent one of THE WHEELS.