+/*
+ * random.c - basic random deviates
+ *
+ * author: Frank Zirkelbach <frank.zirkelbach@physik.uni-augsburg.de>
+ *
+ */
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <math.h>
+
+#include "random.h"
+
+int rand_init(t_random *random,char *randomfile,int logfd) {
+
+ random->status=0;
+
+ if(logfd) random->logfd=logfd;
+
+ if(randomfile==NULL) {
+ random->fd=open("/dev/urandom",O_RDONLY);
+ if(random->fd<0) {
+ perror("open urandom");
+ return -1;
+ }
+ random->status|=RAND_STAT_UDEV;
+ } else {
+ random->fd=open(randomfile,O_RDONLY);
+ if(random->fd<0) {
+ perror("open randomfile");
+ return -1;
+ }
+ }
+ random->buffer=malloc(RAND_BUFSIZE*sizeof(unsigned int));
+ if(random->buffer==NULL) {
+ perror("malloc random buffer");
+ return -1;
+ }
+ random->b_ptr=random->buffer+RAND_BUFSIZE;
+
+ dprintf(random->logfd,"[random] init successfull\n");
+
+ return 0;
+}
+
+
+int rand_close(t_random *random) {
+
+ dprintf(random->logfd,"[random] shutdown\n");
+
+ if(random->buffer) free(random->buffer);
+ if(random->fd) close(random->fd);
+ if(random->logfd) close(random->logfd);
+
+ return 0;
+}
+
+unsigned int rand_get(t_random *random) {
+
+ if(random->b_ptr==random->buffer+RAND_BUFSIZE) {
+ if(random->status&RAND_STAT_VERBOSE)
+ dprintf(random->logfd,
+ "[random] getting new random numbers\n");
+ random->b_ptr=random->buffer;
+ if(!(random->status&RAND_STAT_UDEV)) {
+ lseek(random->fd,0,SEEK_SET);
+ dprintf(random->logfd,
+ "[random] warning, rereading random file\n");
+ }
+ read(random->fd,random->b_ptr,
+ RAND_BUFSIZE*sizeof(unsigned int));
+ if(random->status&RAND_STAT_VERBOSE)
+ dprintf(random->logfd,
+ "[random] got new random numbers\n");
+ }
+
+ return(*(random->b_ptr++));
+}
+
+double rand_get_double(t_random *random) {
+
+ return(1.0*rand_get(random)/(double)(URAND_MAX+1));
+}
+
+double rand_get_double_linear(t_random *random,double a,double b) {
+
+ return((-b+sqrt(b*b+2*a*(b+a/2)*rand_get_double(random)))/a);
+}
+
+double rand_get_gauss(t_random *random) {
+
+ double a,b,w;
+
+ if(random->status&RAND_STAT_GAUSS) {
+ random->status&=~RAND_STAT_GAUSS;
+ return random->gauss;
+ }
+
+ w=0;
+ while((w>=1.0)||(w==0.0)) {
+ a=-2.0*rand_get_double(random)+1.0;
+ b=-2.0*rand_get_double(random)+1.0;
+ w=a*a+b*b;
+ }
+
+ w=sqrt(-2.0*log(w)/w);
+
+ random->gauss=b*w;
+ random->status|=RAND_STAT_GAUSS;
+
+ return(a*w);
+}
+
+unsigned int rand_get_int_linear(t_random *random,unsigned int max,
+ double a,double b) {
+
+ return((int)(rand_get_double_linear(random,a,b)*max));
+}
+
+unsigned int rand_get_reject(t_random *random,unsigned int max_x,
+ unsigned int max_y,unsigned int *graph) {
+
+ unsigned int x,y;
+ unsigned char ok;
+
+ ok=0;
+ while(!ok) {
+ x=(max_x*rand_get_double(random));
+ y=(max_y*rand_get_double(random));
+ if(y<=graph[x]) ok=1;
+ }
+
+ return x;
+}
+