Skip to content

Instantly share code, notes, and snippets.

@lynnporu
Last active November 21, 2020 00:35
Show Gist options
  • Save lynnporu/3906db1a772eee52fba56c20169d9022 to your computer and use it in GitHub Desktop.
Save lynnporu/3906db1a772eee52fba56c20169d9022 to your computer and use it in GitHub Desktop.
Linear congruence pseudorandom generator aka Lehmer generator implementation in C for Linux
/*
This is C implementation of pseudorandom numbers generator. It
contains just one type of generators (linear congruence generator
aka Lehmer generator), but you can add your own generators as
well.
This file can be compiled as main with the following directive:
gcc -Wall rand.c -o bin/rand
Following flags are available:
-DOMIT_RAND_MAIN Do not include main of rand.c in your code.
*/
#include "rand.h"
int64_t RAND_SEED = 23;
// Variables for linear congruence generator (use generator=0)
uint32_t LINCON_RAND_M = 536870911;
uint64_t LINCON_RAND_A = 4096;
uint64_t LINCON_RAND_C = 6765;
#ifndef OMIT_RAND_MAIN
/* If more random generators will be implementer in the future, main() will chose
among them using `generator' variable.
0 - linear congruence generator.
*/
char print_to_file = 0;
FILE* fout;
#define LINEAR_CONG_RAND_GENERATOR 0
static char generator = LINEAR_CONG_RAND_GENERATOR;
static char measure_mode = 0;
static uint64_t max_counter = 1;
int main(int argc, char** argv){
int argument = 0;
while( (argument = getopt(argc, argv, "hm:a:c:x:n:ro:l")) != -1 ){
uint64_t number_arg = 0;
switch(argument){
case 'h':
printf(
"This program implements generators of random numbers Available parameters\n"
"listed below.\n"
" -h Prints this message;\n"
" -m [0 < num < UINT64_MAX] Use with -l. Modulus, by default = 2^29 - 1;\n"
" -a [0 < a < m] Use with -l. Multiplier, by default = 16^3;\n"
" -c [0 <= c < m] Use with -l. Increment, by default = 6765;\n"
" -x [num < UINT64_MAX] Use with -l. Start value, by default = 23;\n"
" -n [0 < num < UINT64_MAX] Number of randoms to compute, by default = 1;\n"
" -r Measure length of the loop and type it;\n"
" -o [..] Print to the file instead of stdout;\n"
" -l Use linear congruence generator (default).\n"
);
return 0;
break;
case 'l':
generator = LINEAR_CONG_RAND_GENERATOR;
break;
case 'r':
measure_mode = 1;
break;
case 'o':
print_to_file = 1;
if((fout = fopen(optarg, "w+")) == NULL){
EMERGENCY("Cannot open output file");
exit(EXIT_FAILURE);
}
continue;
case 'm':
number_arg = atoi(optarg);
if(number_arg <= 0){
EMERGENCY("Modulus should be 0 < m < INT64_MAX");
exit(EXIT_FAILURE);
}
else LINCON_RAND_M = (uint64_t)number_arg;
break;
case 'a':
number_arg = atoi(optarg);
if(number_arg <= 0 || number_arg > LINCON_RAND_M){
EMERGENCY("Multiplier should be 0 < a < modulus");
exit(EXIT_FAILURE);
}
else LINCON_RAND_A = (uint64_t)number_arg;
break;
case 'c':
number_arg = atoi(optarg);
if(number_arg < 0 || number_arg > LINCON_RAND_M){
EMERGENCY("Increment should be 0 <= c <= modulus");
exit(EXIT_FAILURE);
}
else LINCON_RAND_C = (uint64_t)number_arg;
break;
case 'x':
number_arg = atoi(optarg);
RAND_SEED = number_arg;
break;
case 'n':
number_arg = atoi(optarg);
if(number_arg < 0){
EMERGENCY("number_arg should be 0 < n < INT64_MAX");
exit(EXIT_FAILURE);
}
else max_counter = (uint64_t)number_arg;
break;
}
}
if(measure_mode){
uint64_t period = 0;
int64_t start = RAND_SEED;
do rand_lincon();
while(start != RAND_SEED && ++period);
IO_PRINT("%ld\n", period);
return 0;
}
for(unsigned i = 0; i < max_counter; i++)
switch(generator){
case LINEAR_CONG_RAND_GENERATOR:
IO_PRINT("%ld\n", rand_lincon());
break;
}
if(print_to_file) fclose(fout);
return 0;
}
#endif
/* Linear congruence generator.
*/
__attribute__((hot))
uint64_t rand_lincon(void){
return (
RAND_SEED =
(LINCON_RAND_A * RAND_SEED + LINCON_RAND_C) % LINCON_RAND_M
);
}
#ifndef H_RAND
#define H_RAND
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include "io.h"
extern int64_t RAND_SEED;
// Variables for linear congruence generator (use generator=0)
extern uint32_t LINCON_RAND_M;
extern uint64_t LINCON_RAND_A;
extern uint64_t LINCON_RAND_C;
uint64_t rand_lincon(void);
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment