123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317 |
- #include <errno.h>
- #include <fcntl.h>
- #include <getopt.h>
- #include <math.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <sys/random.h>
- #include <sys/stat.h>
- #include <sys/types.h>
- #include <unistd.h>
-
- #define NTEST 3
-
- struct rand_ctx
- {
- unsigned char buf[4096];
- int cur_read;
- };
-
- static struct option long_opts[] = {
- {"iter", required_argument, 0, 'i'},
- {"resolution", required_argument, 0, 'r'},
- {"relative", no_argument, 0, 'R'},
- {"help", no_argument, 0, 'h'},
- {0, 0, 0, 0}
- };
-
- void usage(const char name[])
- {
- dprintf(2, "Usage %s [-i ITER] [-r RESOLUTION] [-R]\n\
- \t-i, --iter Iteration count\n\
- \t-r, --resolution Number of dice faces\n\
- \t-R, --relative Output relative count instead of absolute\n\
- \t-h, --help Display this help and exit\n", name);
- }
-
- void rand_ctx_init(struct rand_ctx *ctx)
- {
- ctx->cur_read = -1;
- }
-
- int randbits(char count, unsigned long *bits, struct rand_ctx *ctx)
- {
- int ret;
-
- *bits = 0;
-
- if(count < 0 || count > 8*sizeof(unsigned long))
- {
- return -1;
- }
-
- if(sizeof(ctx->buf) - ctx->cur_read < (count/8)+1)
- {
- ctx->cur_read = -1;
- }
- if(ctx->cur_read < 0)
- {
- while(1)
- {
- ret = getrandom(ctx->buf, sizeof(ctx->buf), 0);
- if(ret < 0) {
- if(errno == EINTR) { continue; }
- perror("Unable to get random bytes");
- return -2;
- }
- break;
- }
- ctx->cur_read = 0;
- }
-
- do {
- if(count < 8)
- {
- *bits <<= count;
- *bits |= ctx->buf[ctx->cur_read] & ((1<<count)-1);
- count = 0;
- }
- else
- {
- *bits <<= 8;
- *bits |= ctx->buf[ctx->cur_read];
- count -= 8;
- }
- ctx->cur_read++;
- }while(count);
-
- return 0;
- }
-
- int std_rand(unsigned long iterations, unsigned char resolution, unsigned int *result)
- {
- unsigned long bits;
- struct rand_ctx ctx;
- char nbits;
-
- nbits = (char)ceilf(log2f(resolution));
-
- rand_ctx_init(&ctx);
-
- for(unsigned long i = 0; i<iterations; i++)
- {
- do
- {
- if(randbits(nbits, &bits, &ctx) < 0) {
- perror("Unable to get random bits");
- return -1;
- }
- }while(bits > resolution-1);
- result[bits]++;
- }
-
- return 0;
- }
-
- int mod_rand(unsigned long iterations, unsigned char resolution, unsigned int *result)
- {
- unsigned long bits;
-
- struct rand_ctx ctx;
-
- rand_ctx_init(&ctx);
-
- for(unsigned long i = 0; i<iterations; i++)
- {
- if(randbits(8, &bits, &ctx) < 0) {
- perror("Unable to get random bits");
- return -1;
- }
- result[bits%resolution]++;
- }
- return 0;
- }
-
- int prop_rand(unsigned long iterations, unsigned char resolution, unsigned int *result)
- {
- unsigned long bits;
-
- struct rand_ctx ctx;
-
- rand_ctx_init(&ctx);
-
- for(unsigned long i = 0; i<iterations; i++)
- {
- if(randbits(8, &bits, &ctx) < 0)
- {
- perror("Unable to get random bits");
- return -1;
- }
- result[(bits * resolution) / 256]++;
- }
- return 0;
- }
-
- void print_result(unsigned char resolution, unsigned int *result)
- {
- printf("[");
- for(int i=0; i<resolution; i++)
- {
- printf("%d%s", result[i], i<resolution-1?", ":"");
- }
- printf("]\n");
- }
-
- void print_results(unsigned char resolution, unsigned int *results[NTEST])
- {
- for(int i=0; i<resolution; i++)
- {
- printf("%d %d ", resolution, i);
- for(int j=0; j<NTEST; j++)
- {
- printf("%d ", results[j][i]);
- }
- printf("\n");
- }
- }
-
- void print_results_rel(unsigned char resolution, unsigned long iterations,
- unsigned int *results[NTEST])
- {
- long double res;
- for(int i=0; i<resolution; i++)
- {
- printf("%d %f ", resolution, (double)i / resolution);
- for(int j=0; j<NTEST; j++)
- {
- res = (results[j][i] * resolution);
- res /= iterations;
- printf("%Lf ", res);
- }
- printf("\n");
- }
- }
-
- int main(int argc, char *argv[]) {
-
- unsigned char resolution;
- unsigned long iterations;
- short relative;
- long long tmp_ll;
- unsigned int *results[NTEST];
-
- relative = 0;
- iterations = 0x1000;
- resolution = 100;
-
- while (1)
- {
- int c;
- int option_index = 0;
- char *arg_endp;
-
- c = getopt_long(argc, argv, "i:r:Rh",
- long_opts, &option_index);
- if(c == -1) { break; }
- switch(c)
- {
- case 'i':
- tmp_ll = strtoll(optarg, &arg_endp, 0);
- if (*arg_endp != '\0' || optarg == arg_endp)
- {
- dprintf(2, "Unable to parse iteration count '%s' invalid from '%s'\n", optarg, arg_endp);
- usage(argv[0]);
- exit(1);
- }
- if(tmp_ll <= 0)
- {
- dprintf(2, "Invalid iteration count %lld\n",
- tmp_ll);
- usage(argv[0]);
- exit(1);
- }
- iterations = tmp_ll;
- break;
- case 'r':
- tmp_ll = strtoll(optarg, &arg_endp, 0);
- if (*arg_endp != '\0' || optarg == arg_endp)
- {
- dprintf(2, "Unable to parse resolution '%s' invalid from '%s'\n", optarg, arg_endp);
- usage(argv[0]);
- exit(1);
- }
- if(tmp_ll <= 0)
- {
- dprintf(2, "Invalid resolution %lld\n",
- tmp_ll);
- usage(argv[0]);
- exit(1);
- }
- else if(tmp_ll > 255)
- {
- dprintf(2, "Too big resolution %lld (max 255)\n",
- tmp_ll);
- usage(argv[0]);
- exit(1);
- }
- resolution = tmp_ll;
- break;
- case 'R':
- relative = 1;
- break;
- case 'h':
- usage(argv[0]);
- exit(0);
- case '?':
- break;
- }
- }
- if(optind < argc)
- {
- dprintf(2, "Invalid arguments : ");
- for(int i=optind; i<argc; i++)
- {
- dprintf(2, "'%s' ", argv[i]);
- }
- dprintf(2, "\n");
- usage(argv[0]);
- exit(1);
- }
-
- if(relative)
- {
- iterations = iterations * resolution;
- }
-
- for(int i=0; i<NTEST; i++)
- {
- if( !(results[i] = malloc(sizeof(unsigned int) * resolution)) )
- {
- perror("Unable to allocate results array");
- return 1;
- }
- bzero(results[i], sizeof(unsigned int)*resolution);
- }
-
- std_rand(iterations, resolution, results[0]);
- mod_rand(iterations, resolution, results[1]);
- prop_rand(iterations, resolution, results[2]);
-
- if(relative)
- {
- print_results_rel(resolution, iterations, results);
- }
- else
- {
- print_results(resolution, results);
- }
-
- for(int i=0; i<NTEST; i++)
- {
- free(results[i]);
- }
-
- return 0;
- }
|