/*
* This program is an example of how to shuffle an array.
*
* It is provided for illustrative purposes,
* It is placed in the public domain, thus has no copyright.
*
* Comments and bug reports about this program should be sent
* via email to scott@helsbreth.org
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define ulong unsigned long
/* ----------------------------------------------------------------------
COMBO
a simple but very good combination generator.
It combines, by addition mod 2^32,
x(n)=x(n-1)*x(n-2) mod 2^32
and
y(n)=30903*y(n-1) + carry mod 2^16
The period of the first is 3*2^29, on odd integers, and the
period of the second, a multiply-with-carry generator, is
30903*2^15-1=1012629503, so the period of combo exceeds 2^60.
This generator is simple to program in Fortran or C and quite
fast.
*/
/*
Simple combo, period > 2^60.5
x(n)=x(n-1)*x(n-2) mod 2^32 added to
period of x(n)=x(n-1)*x(n-2) is 3*2^29 if both seeds are
odd, and one is +or-3 mod 8.
easy to ensure: replace seed x with 8*seed+3, and y with 2*seed+1
*/
static ulong combo_x = 3;
static ulong combo_y = 1;
static ulong combo_z = 1;
static ulong combo_v = 0;
void seed_rand_combo(ulong seed) {
combo_x = seed * 8 + 3;
combo_y = seed * 2 + 1;
combo_z = seed | 1;
combo_v = 0;
}
ulong rand_combo(void) {
combo_v = combo_x * combo_y;
combo_x = combo_y;
combo_y = combo_v;
combo_z = (combo_z & 65535) * 30903 + (combo_z >> 16);
return combo_y + combo_z;
}
#define RAND_MAX_COMBO ((unsigned long) 4294967295)
/* ----------------------------------------------------------------------
range
returns a number between 0 and N-1
without any bias.
*/
int range(int n) {
unsigned long div;
int r;
div = RAND_MAX_COMBO/n;
do {
r = rand_combo() / div;
} while (r >= n);
return r;
}
/* -------------------------------------------------------------- */
/* ----------------------------------------------------------------------
range2
returns an integer between low and high inclusive
*/
int range2(int low, int high) {
return low + range(high-low+1);
}
/* -------------------------------------------------------------- */
#define NUMBER_OF_ELEMENTS 20
int main() {
int i, s, t;
int array[NUMBER_OF_ELEMENTS];
/* initialize the array */
for (i=0; i<NUMBER_OF_ELEMENTS; i++) {
array[i] = i;
}
/*
'Randomize' the random number generator so it won't
produce the same sequence each time.
*/
seed_rand_combo( (ulong) time(NULL) );
/*
Now 'shuffle' the array.
The method is; pick a random element in the array
and swap it with the first element. Then pick a random
element from the rest of the array and swap with the second
and so on.
*/
for (i=0; i<NUMBER_OF_ELEMENTS; i++) {
/* Pick a random element */
s = range2(i, NUMBER_OF_ELEMENTS-1);
/* swap them */
t = array[i];
array[i] = array[s];
array[s] = t;
}
for (i=0; i<NUMBER_OF_ELEMENTS; i++) {
printf("%d ", array[i]);
}
printf("\n");
return 0;
}