Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>The problem is that you're doing a modulo operation. This would be no problem if <code>RAND_MAX</code> would be evenly divisible by your modulus, but usually that is not the case. As a very contrived example, assume <code>RAND_MAX</code> to be 11 and your modulus to be 3. You'll get the following possible random numbers and the following resulting remainders:</p> <pre><code>0 1 2 3 4 5 6 7 8 9 10 0 1 2 0 1 2 0 1 2 0 1 </code></pre> <p>As you can see, 0 and 1 are slightly more probable than 2.</p> <p>One option to solve this is rejection sampling: By disallowing the numbers 9 and 10 above you can cause the resulting distribution to be uniform again. The tricky part is figuring out how to do so efficiently. A very nice example (one that took me two days to understand <em>why</em> it works) can be found in Java's <a href="http://docs.oracle.com/javase/7/docs/api/java/util/Random.html#nextInt%28int%29" rel="nofollow noreferrer"><code>java.util.Random.nextInt(int)</code></a> method.</p> <p>The reason why Java's algorithm is a little tricky is that they avoid slow operations like multiplication and division for the check. If you don't care too much you can also do it the naïve way:</p> <pre><code>int n = (int)(max - min + 1); int remainder = RAND_MAX % n; int x, output; do { x = rand(); output = x % n; } while (x &gt;= RAND_MAX - remainder); return min + output; </code></pre> <p><strong>EDIT:</strong> Corrected a fencepost error in above code, now it works as it should. I also created a little sample program (C#; taking a uniform PRNG for numbers between 0 and 15 and constructing a PRNG for numbers between 0 and 6 from it via various ways):</p> <pre><code>using System; class Rand { static Random r = new Random(); static int Rand16() { return r.Next(16); } static int Rand7Naive() { return Rand16() % 7; } static int Rand7Float() { return (int)(Rand16() / 16.0 * 7); } // corrected static int Rand7RejectionNaive() { int n = 7, remainder = 16 % n, x, output; do { x = Rand16(); output = x % n; } while (x &gt;= 16 - remainder); return output; } // adapted to fit the constraints of this example static int Rand7RejectionJava() { int n = 7, x, output; do { x = Rand16(); output = x % n; } while (x - output + 6 &gt; 15); return output; } static void Test(Func&lt;int&gt; rand, string name) { var buckets = new int[7]; for (int i = 0; i &lt; 10000000; i++) buckets[rand()]++; Console.WriteLine(name); for (int i = 0; i &lt; 7; i++) Console.WriteLine("{0}\t{1}", i, buckets[i]); } static void Main() { Test(Rand7Naive, "Rand7Naive"); Test(Rand7Float, "Rand7Float"); Test(Rand7RejectionNaive, "Rand7RejectionNaive"); } } </code></pre> <p>The result is as follows (pasted into Excel and added conditional coloring of cells so that differences are more apparent):</p> <p><img src="https://i.stack.imgur.com/HKeOl.png" alt="enter image description here"></p> <p>Now that I fixed my mistake in above rejection sampling it works as it should (before it would bias 0). As you can see, the float method isn't perfect at all, it just distributes the biased numbers differently.</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload