1 /*
2  * Copyright 2018 Oticon A/S
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 #include <stdlib.h>
7 #include <string.h>
8 #include <math.h>
9 #include <complex.h>
10 #include "bs_tracing.h"
11 #include "bs_types.h"
12 #include "bs_rand_inline.h"
13 
14 /**
15  * Initialize the random generators
16  */
bs_random_init(unsigned int seed)17 int bs_random_init(unsigned int seed){
18   srandom(seed);
19   srand(seed);
20   return 0;
21 }
22 
23 /**
24  * Free any memory this module may have allocated
25  */
bs_random_free()26 void bs_random_free(){
27 
28 }
29 
30 /**
31  * Generate a Gausian random number N(0,1): with mean 0 and variance 1
32  * In general to get a N(ave,std) do:
33  *   Random_Gaus()*std + ave;
34  *
35  * It uses the Marsaglia polar method:
36  *  http://en.wikipedia.org/wiki/Marsaglia_polar_method
37  *  Based on the "MIT like" licensed code
38  *  ftp://ftp.taygeta.com/pub/c/boxmuller.c:
39  *  "(c) Copyright 1994, Everett F. Carter Jr.
40  *       Permission is granted by the author to use
41  *       this software for any application provided this
42  *       copyright notice is preserved."
43  *
44  *  but with div by 0 protection
45  */
bs_random_Gaus()46 double bs_random_Gaus(){
47   double x,w;
48   static double y;
49   static int use_last = 0;
50   double toreturn;
51 
52   if (use_last == 0) {
53     do {
54       x = 2*((double)random() / RAND_MAX)-1;
55       y = 2*((double)random() / RAND_MAX)-1;
56 
57       w = x * x + y * y;
58     } while (w >= 1 || w == 0);
59 
60     w = sqrt(-2.0 * log(w) / w);
61     toreturn = x * w;
62     y = y * w;
63   } else {
64     toreturn = y;
65   }
66 
67   use_last = 1 - use_last;
68 
69   return toreturn;
70 }
71 
72 /**
73  * Like Random_Gaus but return a complex double instead
74  * Returns a sample of a N(0,1) + 1i*N(0,1) with uncorrelated I and Q parts
75  */
bs_random_Gaus_c()76 double complex bs_random_Gaus_c(){
77   double x, y, w;
78   double complex toreturn;
79 
80     do {
81       x = 2*((double)random() / RAND_MAX)-1;
82       y = 2*((double)random() / RAND_MAX)-1;
83 
84       w = x * x + y * y;
85     } while(w >= 1 || w == 0);
86     w = sqrt(-2.0 * log(w) / w);
87 
88     toreturn = x * w + ( y * w )*I;
89 
90   return toreturn;
91 }
92 
93 /**
94  * Fill in a buffer of size <size> with complex random gausian numbers
95  * each a sample of a N(0,1) + 1i*N(0,1) with uncorrelated I and Q parts
96  */
bs_random_Gaus_c_buffer(double complex * buffer,uint size)97 void bs_random_Gaus_c_buffer(double complex* buffer, uint size){
98   double x, y, w;
99   uint i;
100 
101   //TOOPT: this takes a sizeable amount of time for the 2G4_channel_Indoorv1,
102   // it could make sense to optimize it to avoid using log
103   // roughly time is used as follows: log: 383/856, sqrt = 12/856,  random 133*2/856
104   // an option would be: http://en.wikipedia.org/wiki/Ziggurat_algorithm
105 
106   for (i = 0 ; i < size; i++){
107     do {
108       x = 2*((double)random() / RAND_MAX)-1;
109       y = 2*((double)random() / RAND_MAX)-1;
110 
111       w = x * x + y * y;
112     } while(w >= 1 || w == 0);
113     w = sqrt(-2.0 * log(w) / w);
114 
115     buffer[i] = x * w + ( y * w )*I;
116   }
117 }
118 
119 /**
120  * Return a Generalized Pareto random number (double)
121  * Where the generalized pareto parameters are (like in MATLAB)
122  *  k: shape (-inf..inf) (xi for some authors)
123  *  sigma: scale (0..inf)
124  *  theta: location (-inf..inf) (mu for some authors)
125  */
bs_random_GPRND(double k,double sigma,double theta)126 double bs_random_GPRND(double k, double sigma, double theta){
127   double u = ( ((double)random()) / ((double)RAND_MAX)); //U(0,1) : uniformly distributed random number from 0 to 1
128   double r;
129   if ( fabs(k) < 0.005 ){ //effectively there is no difference in the shape of the distribution from k = 0
130     r = -log(u);
131   } else {
132     r = expm1(-k*log(u)) / k; // ( u^(-k) - 1 ) / k
133   }
134   r = theta + sigma*r;
135   return r;
136 }
137 
138 /**
139  * Draws a bit {0,1}
140  */
bs_random_bit()141 char bs_random_bit(){
142   return ( random() & 1 );
143 }
144 
145 /**
146  * Draws a number from a U[0,1]
147  */
bs_random_uniform()148 double bs_random_uniform(){
149   return ( ((double)random()) / ((double)RAND_MAX));
150 }
151 
152 /**
153  * Draws a number from a U[a,b] (both double)
154  */
bs_random_uniformR(double a,double b)155 double bs_random_uniformR(double a, double b){
156   double u = ( ((double)random()) / ((double)RAND_MAX));
157   u *=(b-a);
158   u +=a;
159   return u;
160 }
161 
162 /**
163  * Draws a number from a U[a,b] (both integer)
164  *  b > a
165  */
bs_random_uniformRi(int a,int b)166 int bs_random_uniformRi(int a, int b){
167   if ( b <= a )
168     return a; //safety feature
169 
170   int i_u;
171   while (1) {
172     double u = ( ((double)random()) / ((double)RAND_MAX)); //[0..1]
173     u *=(b+1-a); //[0.. (b+1-a)]
174     u +=a;       //[a..b+1]
175     i_u = floor(u); //[a,..,b+ups]
176     if (i_u <= b) //although extremely unlikely, we could get RAND_MAX out of the random generator and otherwise produce b+1
177       break;
178   }
179   return i_u;
180 }
181 
182 /*
183  * This function is deprecated, consider using bs_random_buffer(&result, sizeof(uint32_t)) instead
184  * Note this function is buggy, as it only produces a 31bit random number.
185  */
bs_random_uint32()186 uint32_t bs_random_uint32(){
187   return (uint32_t)random();
188 }
189 
190 /*
191  * Fill a buffer with <length> random bytes
192  */
bs_random_buffer(char * buffer,size_t size)193 void bs_random_buffer(char *buffer, size_t size) {
194   unsigned int bits_ready = 0;
195   uint64_t value = 0;
196 
197   while (size) {
198     value = value | ((uint64_t)random() << bits_ready);
199     /* The host random() provides a number between 0 and 2**31-1. Bit 32 is always 0 */
200     bits_ready += 31;
201 
202     size_t to_copy = BS_MIN(size, bits_ready / 8);
203 
204     memcpy(buffer, &value, to_copy);
205     buffer += to_copy;
206     size -= to_copy;
207     value >>= to_copy * 8;
208     bits_ready -= to_copy * 8;
209   }
210 }
211 
212 /**
213  * Do a binomial drop, that is produce a realization of B(n,p)
214  *
215  * n: number of independent trials
216  * probability: probability p, for each trial, a number between 0 (0.0) and RAND_PROB_1 (1.0)
217  */
bs_random_Binomial(uint n,uint32_t probability)218 uint bs_random_Binomial(uint n, uint32_t probability){
219   uint acc = 0;
220   for (uint i = 0; i < n; i ++) {
221     acc += bs_random_Bern(probability);
222   }
223   return acc;
224 }
225