/* gcc rng1.c -o rng1 -Wall -ansi -pedantic Random number generator with one-dimensional r=2 cellular automata Example: ./rng1 1164622485 */ #include #include #include #define PROGRAM_NAME "rng1" #define DEBUG 1 #define MALLOC(var,size) \ (var) = malloc(size); \ if(!(var)) \ fprintf(stderr, "%s:%d: out of memory\n", __FILE__, __LINE__), \ exit(EXIT_FAILURE); \ #define ASSERT(x) \ if(!(x)) \ fprintf(stderr, "%s:%d: ASSERT failed\n", __FILE__, __LINE__), \ exit(EXIT_FAILURE); typedef struct CA CA; /* Iterate the CA */ void ca_iterate (CA *ca, unsigned int steps); /* Create the cellular automaton */ CA * ca_create (unsigned int width, unsigned int rule); /* Set the rule for the transition table */ void ca_rule_set (CA *ca, unsigned int rule); /* Free the memory held by the cellular automaton */ void ca_destroy (CA *ca); /* Initialize the CA grid using the systems "rand" function */ void ca_init_random (CA *ca); /* Initialize the CA using a single cell in the center */ void ca_init_single(CA *ca); /* Adds ca->width bits to the output buffer */ int ca_to_file (CA *ca, int nbytes, FILE *p); int main(int argc, char *argv[]) { CA *ca; char *filename = "out.rnd"; FILE *p; int nbytes; unsigned rule; srand(time(NULL)); nbytes = 1024*1024*10; if (argc != 2) { fprintf(stderr, "usage: %s rule\n", PROGRAM_NAME); exit(EXIT_FAILURE); } sscanf(argv[1], "%u", &rule); if (DEBUG) { printf("rule %u\n", rule); } ca = ca_create(512, rule); if (! (p = fopen(filename, "wb"))) { perror("fopen"); exit(EXIT_FAILURE); } ca_init_random(ca); while (nbytes >= 0) { ca_iterate(ca, 1); nbytes = ca_to_file(ca, nbytes, p); } fclose(p); ca_destroy(ca); return EXIT_SUCCESS; } struct CA { unsigned int width; unsigned int rule; char *cell; }; CA * ca_create(unsigned int width, unsigned int rule) { CA *new; MALLOC(new, sizeof(CA)); new->rule = rule; new->width = width; MALLOC(new->cell, width + 2); return new; } void ca_rule_set(CA *ca, unsigned int rule) { ASSERT(ca); ASSERT(ca->cell); ca->rule = rule; } void ca_destroy(CA *ca) { ASSERT(ca); ASSERT(ca->cell); free(ca->cell); free(ca); } void ca_init_random(CA *ca) { unsigned int i; for (i = 0; i < ca->width; i++) { char n = rand() % 2; ca->cell[i] = n; } } /* * Now we iterate the CA inplace. * I sould've done this a long time ago. * * The ca array _must_ have two extra locations. */ void ca_iterate (CA *ca, unsigned int steps) { unsigned int i, col, lookup; ASSERT(ca); ASSERT(steps); ASSERT(ca->cell); ASSERT(ca->width > 10); for (i = 0; i < steps; i++) { ca->cell[ca->width] = ca->cell[0]; ca->cell[ca->width + 1] = ca->cell[1]; lookup = ca->cell[ca->width - 2] << 3 | ca->cell[ca->width - 1] << 2 | ca->cell[0] << 1 | ca->cell[1]; for (col = 0; col < ca->width; col++) { lookup = (lookup << 1 | ca->cell[col + 2]) & 0x001F; ASSERT(lookup >=0 && lookup <= 31); ca->cell[col] = (ca->rule & (1 << lookup)) >> lookup; } } } /* returns (nbytes - bytes_written) */ /* TODO: Using static variables to keep the state */ int ca_to_file (CA *ca, int nbytes, FILE *p) { static int CACHE_VAR = 0; static int CACHE_COUNT = 0; int i; ASSERT(ca); ASSERT(p); for (i = 0; i < ca->width ;++i) { CACHE_VAR |= ca->cell[i] << CACHE_COUNT; CACHE_COUNT++; if (CACHE_COUNT == sizeof (int) * 8) { fwrite (&CACHE_VAR, sizeof (int), 1, p); CACHE_COUNT = 0; CACHE_VAR = 0; nbytes -= sizeof (int); } } return nbytes; }