cl-pcg/usage/index.html @ 0f6bab39c0f4
default tip
adopt: Update site.
author |
Steve Losh <steve@stevelosh.com> |
date |
Thu, 13 Jun 2024 13:05:28 -0400 |
parents |
511800267161 |
children |
(none) |
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<title>Usage / cl-pcg</title>
<link rel="stylesheet" href="../_dmedia/tango.css"/>
<link rel="stylesheet/less" type="text/css" href="../_dmedia/style.less"/>
<script src="../_dmedia/less.js" type="text/javascript">
</script>
</head>
<body class="content">
<div class="wrap">
<header><h1><a href="..">cl-pcg</a></h1></header>
<div class="markdown">
<h1 id="usage"><a href="">Usage</a></h1><p><code>cl-pcg</code> is a <a href="http://www.pcg-random.org/">permuted congruential generator</a> implementation in pure
Common Lisp. It provides a high-level API and a low-level API.</p>
<p>PCGs are <strong>not</strong> cryptographically secure. If you need that, look elsewhere.</p>
<div class="toc">
<ul>
<li><a href="#the-high-level-api">The High-Level API</a><ul>
<li><a href="#creating-a-generator">Creating a Generator</a></li>
<li><a href="#generating-numbers">Generating Numbers</a></li>
<li><a href="#the-global-generator">The Global Generator</a></li>
<li><a href="#advancing-rewinding">Advancing & Rewinding</a></li>
</ul>
</li>
<li><a href="#the-low-level-api">The Low-Level API</a></li>
<li><a href="#limitations">Limitations</a></li>
</ul></div>
<h2 id="the-high-level-api">The High-Level API</h2>
<p>The high-level API is what you should start (and probably end) with. It
typechecks the arguments you pass in and offers a nice interface for generating
random numbers.</p>
<h3 id="creating-a-generator">Creating a Generator</h3>
<p>To create a generator you can use the <code>make-pcg</code> function:</p>
<div class="codehilite"><pre><span/><span class="p">(</span><span class="nb">defparameter</span> <span class="vg">*gen*</span> <span class="p">(</span><span class="nv">make-pcg</span><span class="p">))</span>
</pre></div>
<p><code>make-pcg</code> takes two keyword parameters:</p>
<ul>
<li><code>:seed</code> should be an <code>(unsigned-byte 64)</code>. If omitted a random seed will be
generated with the underlying implementation's <code>cl:random</code> function.</li>
<li><code>:stream-id</code> should be an <code>(unsigned-byte 32)</code>. The default is <code>0</code>. Streams
provide a way to "split" a PCG into multiple generators — check out the PCG
site for more information on this.</li>
</ul>
<p>Once you've got a PCG object you can use it to generate some numbers.</p>
<h3 id="generating-numbers">Generating Numbers</h3>
<p>You can use the <code>pcg-random</code> function to generate random numbers:</p>
<div class="codehilite"><pre><span/><span class="p">(</span><span class="nb">defparameter</span> <span class="vg">*gen*</span> <span class="p">(</span><span class="nv">make-pcg</span><span class="p">))</span>
<span class="p">(</span><span class="nv">pcg-random</span> <span class="vg">*gen*</span> <span class="mi">10</span><span class="p">)</span>
<span class="c1">; => a random number from 0 (inclusive) to 10 (exclusive)</span>
</pre></div>
<p><code>pcg-random</code> is flexible and takes a number of optional arguments to help you
generate the kinds of numbers you need. Its lambda list looks like this:</p>
<div class="codehilite"><pre><span/><span class="p">(</span><span class="nv">pcg</span> <span class="nv">bound</span> <span class="k">&optional</span> <span class="nb">max</span> <span class="nv">inclusive?</span><span class="p">)</span>
</pre></div>
<p>If only <code>bound</code> is given, the function acts much like <code>cl:random</code>.</p>
<p>If <code>max</code> is also given, a random number in <code>[bound, max)</code> is chosen.</p>
<p>If <code>inclusive?</code> is also given, a random number in <code>[bound, max]</code> is chosen.</p>
<p>For example:</p>
<div class="codehilite"><pre><span/><span class="p">(</span><span class="nb">defparameter</span> <span class="vg">*gen*</span> <span class="p">(</span><span class="nv">make-pcg</span><span class="p">))</span>
<span class="p">(</span><span class="nv">pcg-random</span> <span class="vg">*gen*</span> <span class="mi">10</span><span class="p">)</span> <span class="c1">; => [0, 10)</span>
<span class="p">(</span><span class="nv">pcg-random</span> <span class="vg">*gen*</span> <span class="mi">15</span> <span class="mi">28</span><span class="p">)</span> <span class="c1">; => [15, 28)</span>
<span class="p">(</span><span class="nv">pcg-random</span> <span class="vg">*gen*</span> <span class="mi">15</span> <span class="mi">28</span> <span class="no">t</span><span class="p">)</span> <span class="c1">; => [15, 28] <- inclusive endpoint!</span>
</pre></div>
<p><code>inclusive?</code> is treated as a generalized boolean, so you can write <code>(pcg-random
gen -10 10 :inclusive)</code> if you feel it reads better.</p>
<p><code>pcg-random</code> can also generate <code>single-float</code>s if <code>bound</code> and/or <code>max</code> are given
as <code>single-float</code>s:</p>
<div class="codehilite"><pre><span/><span class="p">(</span><span class="nb">defparameter</span> <span class="vg">*gen*</span> <span class="p">(</span><span class="nv">make-pcg</span><span class="p">))</span>
<span class="p">(</span><span class="nv">pcg-random</span> <span class="vg">*gen*</span> <span class="mf">10.0</span><span class="p">)</span> <span class="c1">; => [0.0, 10.0]</span>
<span class="p">(</span><span class="nv">pcg-random</span> <span class="vg">*gen*</span> <span class="mi">0</span> <span class="mf">10.0</span><span class="p">)</span> <span class="c1">; => [0.0, 10.0]</span>
<span class="p">(</span><span class="nv">pcg-random</span> <span class="vg">*gen*</span> <span class="mf">-1.0</span> <span class="mf">1.0</span><span class="p">)</span> <span class="c1">; => [-1.0, 1.0]</span>
</pre></div>
<h3 id="the-global-generator">The Global Generator</h3>
<p>If you don't want to bother creating a fresh PCG object you can pass <code>t</code> to the
high-level API to use a globally-defined one:</p>
<div class="codehilite"><pre><span/><span class="p">(</span><span class="nv">pcg-random</span> <span class="no">t</span> <span class="mi">10</span><span class="p">)</span>
</pre></div>
<h3 id="advancing-rewinding">Advancing & Rewinding</h3>
<p>Sometimes it can be useful to advance or rewind a generator by a certain number
of steps. The <code>(pcg-advance pcg steps)</code> and <code>(pcg-rewind pcg steps)</code> functions
can be used to do this:</p>
<div class="codehilite"><pre><span/><span class="p">(</span><span class="nb">defparameter</span> <span class="vg">*gen*</span> <span class="p">(</span><span class="nv">make-pcg</span><span class="p">))</span>
<span class="c1">;; Get three numbers</span>
<span class="p">(</span><span class="nv">pcg-random</span> <span class="vg">*gen*</span> <span class="mi">1000</span><span class="p">)</span> <span class="c1">; => 708</span>
<span class="p">(</span><span class="nv">pcg-random</span> <span class="vg">*gen*</span> <span class="mi">1000</span><span class="p">)</span> <span class="c1">; => 964</span>
<span class="p">(</span><span class="nv">pcg-random</span> <span class="vg">*gen*</span> <span class="mi">1000</span><span class="p">)</span> <span class="c1">; => 400</span>
<span class="c1">;; Rewind three steps</span>
<span class="p">(</span><span class="nv">pcg-rewind</span> <span class="vg">*gen*</span> <span class="mi">3</span><span class="p">)</span>
<span class="c1">;; Get the same three numbers</span>
<span class="p">(</span><span class="nv">pcg-random</span> <span class="vg">*gen*</span> <span class="mi">1000</span><span class="p">)</span> <span class="c1">; => 708</span>
<span class="p">(</span><span class="nv">pcg-random</span> <span class="vg">*gen*</span> <span class="mi">1000</span><span class="p">)</span> <span class="c1">; => 964</span>
<span class="p">(</span><span class="nv">pcg-random</span> <span class="vg">*gen*</span> <span class="mi">1000</span><span class="p">)</span> <span class="c1">; => 400</span>
</pre></div>
<p>These functions are <code>O(log₂(steps))</code> so they'll be fast even for ludicrously
large values of <code>steps</code>.</p>
<h2 id="the-low-level-api">The Low-Level API</h2>
<p>The low-level API is what you want if you need raw speed. It consists of all
functions in the API whose names end in <code>%</code>, like <code>pcg-random%</code>. All of these
functions are <code>declaim</code>ed inline for easy embedding into hot loops.</p>
<p>As an arbitrary example, the main function in this API (<code>pcg-random%</code>) is about
100 bytes of machine code, so it's suitable for inlining when you really need
performance.</p>
<p>The low-level API assumes you will pass in arguments of the correct type. If
you fuck this up, all bets are off. Read the code to figure out exactly what
you need to pass in (or just use the high-level API like a sane person).</p>
<h2 id="limitations">Limitations</h2>
<p>You can only generate 32-bit integers, and only single floats. This will change
whenever I get around to fixing things up.</p>
</div>
<footer><p><i>Made with Lisp and love by <a href="http://stevelosh.com/">Steve Losh</a> in Reykjavík, Iceland.</i></p>
<script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
ga('create', 'UA-15328874-3', 'auto');
ga('send', 'pageview');
</script></footer>
</div>
</body>
</html>