• Welcome to the new COTI server. We've moved the Citizens to a new server. Please let us know in the COTI Website issue forum if you find any problems.
  • We, the systems administration staff, apologize for this unexpected outage of the boards. We have resolved the root cause of the problem and there should be no further disruptions.

Jenkins' Small Noncryptographic PRNG

robject

SOC-14 10K
Admin Award
Marquis
Here it is, in a nutshell, plus methods I use to generate dice rolls. Look how tiny it is!

Note that this is a slightly modified version of the original. For one, it specifically takes the first
64 bits of an MD5 hashcode to seed the generator. Secondly, it uses signed integers -- but since
the algorithm operates on 32 bit numbers, this should be ok if your system uses 64 bit longs.

Code:
use Digest::MD5 qw/md5_hex/;

#################################################################
#
#  As seen on http://www.burtleburtle.net/bob/rand/smallprng.html
#
#################################################################
use integer;
my ($a, $b, $c, $d);

sub rot { ($_[0] << $_[1]) | ($_[0] >> (32-$_[1])) }

sub randint
{
   my $e = ( $a - rot( $b, 27 ) );
      $a = $b ^ rot( $c, 17 );
      $b = ( $c + $d );
      $c = ( $d + $e );
      $d = ( $e + $a );

   return $d;
}

#################################################################
#
#  t5srand(): Seeds the random number generator with a string.
#
#  For world-building, I suggest the following format:
#
#  <galaxy>/<arm>/<sector>/<hex>
#
#  Examples:
#
#  t5srand( "Faraway/1010" );        
#  =>  hex 1010 in the Faraway sector
#
#  t5srand( "Orion/X411/1910" );     
#  =>  hex 1910 in sector X411 of the Orion arm
#
#  t5srand( "MW1/012F/B9900/3201" ); 
#  =>  hex 3210, sector B9900, arm 012F, galaxy MW1
#
#################################################################
sub t5srand 
{
   my $UID  = shift;
   my $hash = '0x' . substr( md5_hex( $UID ), 0, 16 ); # 64 bits

   $a = 0xf1ea5eed;
   $b = $c = $d = eval $hash;
   randint() for 0..19;
}

#################################################################
#
#  Dice-rolling-specific methods.
#  Each of these methods use only *one* call to the RN Generator.
#
#################################################################
sub rand1d { return 1 + ((abs randint()) % 6) }
sub rand2d { my $num = abs randint(); return 2 + ($num % 6) + (($num/6) % 6); }
sub flux   { return rand2d() - 7 }
sub rand1d10 { return ((abs randint()) % 10)  } # 0 thru 9
sub rand1d9  { return ((abs randint()) % 9)+1 } # 1 thru 9

sub rand3d 
{ 
   my $num = abs randint(); 
   return 3 + ($num % 6) + (($num/6) % 6) + (($num/36) % 6); 
}

#################################################################
#
# Extracts 8 d6 rolls, returned in a list, from one random number
#
#################################################################
sub rand8 
{ 
   my $num = abs randint();
   return 1+($num % 6), 
          1+(($num/6) % 6), 
	  1+(($num/36) % 6),
	  1+(($num/216) % 6),
	  1+(($num/1_296) % 6),
	  1+(($num/7_776) % 6),
	  1+(($num/46_656) % 6),
	  1+(($num/279_936) % 6);
}
 
Last edited:
Back
Top