Project Ne10
An Open Optimized Software Library Project for the ARM Architecture
NE10_random.c
1 /*
2  * Copyright 2012-15 ARM Limited and Contributors.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  * * Redistributions of source code must retain the above copyright
8  * notice, this list of conditions and the following disclaimer.
9  * * Redistributions in binary form must reproduce the above copyright
10  * notice, this list of conditions and the following disclaimer in the
11  * documentation and/or other materials provided with the distribution.
12  * * Neither the name of ARM Limited nor the
13  * names of its contributors may be used to endorse or promote products
14  * derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY ARM LIMITED AND CONTRIBUTORS "AS IS" AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19  * DISCLAIMED. IN NO EVENT SHALL ARM LIMITED AND CONTRIBUTORS BE LIABLE FOR ANY
20  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 /*
29  * NE10 Library : test/src/NE10_random.c
30  */
31 
32 #include "NE10_random.h"
33 
34 // Please look at http://en.wikipedia.org/wiki/Linear_congruential_generator
35 // According to this page, these values are the ones used in "glibc"
36 
37 //uint32_t _M = 4294967296L; // 2^32 // modulus, must be 0 < _M
38 const uint32_t _A = 1103515245L; // a, must be 0 < _A < _M
39 const uint32_t _C = 12345L; // c, must be 0 < _C < _M
40 // uint32_t m_X_NM1 = 0; // X(n-1), at first this value is the seed or the start value
41 
42 // generic functions
43 void NE10_rng_init_g (NE10_rng_t *rng, uint32_t seed)
44 {
45  assert (rng != NULL);
46  rng->_private_m_A = _A;
47  rng->_private_m_C = _C;
48  rng->_private_m_X_NM1 = seed;
49 }
50 
51 uint32_t NE10_rng_next_g (NE10_rng_t *rng)
52 {
53  assert (rng != NULL);
54  // Linear Congruential Generator
55  rng->_private_m_X_NM1 = (rng->_private_m_A * rng->_private_m_X_NM1 + rng->_private_m_C); // % _M; // excluded by the nature of using a 32-bit data type
56  return rng->_private_m_X_NM1;
57 }
58 
59 const uint32_t NE10_rng_max_g (NE10_rng_t *rng)
60 {
61  return 0xffffffff; // this is 2^32 - 1
62 }
63 
64 
65 
66 // the same functions using a rng which is shared across the library
67 static NE10_rng_t __NE10_rng; // used as the global random number generator shared across the library
68 
69 void NE10_rng_init (uint32_t seed)
70 {
71  NE10_rng_init_g (&__NE10_rng, seed);
72 }
73 
74 uint32_t NE10_rng_next()
75 {
76  return NE10_rng_next_g (&__NE10_rng);
77 }
78 
79 const uint32_t NE10_rng_max()
80 {
81  return NE10_rng_max_g (NULL);
82 }
83 
84 void NE10_float_rng_init_g (NE10_float_rng_t* float_rng, uint32_t seed)
85 {
86  // we can use [0] for the fraction, [1] for the exponent, and [2] for the sign bit
87 
88  NE10_rng_t seed_generator;
89  NE10_rng_init_g (&seed_generator, seed);
90 
91  NE10_rng_init_g (&float_rng->_private_m_rngs[0], NE10_rng_next_g (&seed_generator));
92  NE10_rng_init_g (&float_rng->_private_m_rngs[1], NE10_rng_next_g (&seed_generator));
93  NE10_rng_init_g (&float_rng->_private_m_rngs[2], NE10_rng_next_g (&seed_generator));
94 }
95 
96 float NE10_float_rng_next_g (NE10_float_rng_t* float_rng)
97 {
98  uint32_t frc, exp, sgn, ret;
99 
100  do
101  {
102  // generate three random numbers
103  frc = NE10_rng_next_g (&float_rng->_private_m_rngs[0]);
104  exp = NE10_rng_next_g (&float_rng->_private_m_rngs[1]);
105  sgn = NE10_rng_next_g (&float_rng->_private_m_rngs[2]);
106 
107  // take the top bits ( the sign uses the 17th bit)
108  frc = (frc >> 9) & 0x7FFFFF ; // (1)b^23
109  exp = ( (exp >> 24) & 0x0000FF) << 23; // (1)b^ 8
110  sgn = ( (sgn >> 16) & 0x000001) << 31;
111 
112  // generate the final float value
113  ret = frc | exp | sgn;
114 
115  }
116  while (IS_NAN_OR_INF (ret) || IS_SUBNORMAL (ret));
117 
118  //memcpy( &__ret, &ret, 1*sizeof(float) );
119  return * ( (float*) &ret);
120 }
121 
122 float NE10_float_rng_max_g (NE10_float_rng_t* float_rng)
123 {
124  return FLT_MAX;
125 }
126 
127 
128 // the same functions using a float_rng which is shared across the library
129 
130 static NE10_float_rng_t __NE10_float_rng; // local array for internal use only
131 
132 void NE10_float_rng_init (uint32_t seed)
133 {
134  NE10_float_rng_init_g (&__NE10_float_rng , seed);
135 }
136 
137 float NE10_float_rng_next()
138 {
139  return NE10_float_rng_next_g (&__NE10_float_rng);
140 }
141 
142 float NE10_float_rng_max()
143 {
144  return NE10_float_rng_max_g (NULL);
145 }
146 
147 // the same as above functions except the range of values are limited
148 
149 #define IS_TOO_SMALL(f) ((fabs(f)<1.0e-3)?1:0)
150 #define IS_TOO_BIG(f) ((fabs(f)>1.0e3)?1:0)
151 
152 static NE10_float_rng_t __NE10_float_rng_limit; // local array for internal use only
153 
154 void NE10_float_rng_limit_init (uint32_t seed)
155 {
156  NE10_float_rng_init_g (&__NE10_float_rng_limit , seed);
157 }
158 
159 float NE10_float_rng_limit_next()
160 {
161  float ret = 0.0f;
162 
163  do
164  {
165  ret = NE10_float_rng_next_g (&__NE10_float_rng_limit);
166  }
167  while (IS_TOO_SMALL (ret) || IS_TOO_BIG (ret));
168 
169  return ret;
170 }
171 
172 float NE10_float_rng_limit_max()
173 {
174  return NE10_float_rng_max_g (NULL);
175 }
176 
177 // the same as above functions except the range of values are limited and all the values are greater than 1.0e-6
178 
179 #define IS_TOO_SMALL_GT1(f) ((fabs(f)<1.0e-6)?1:0)
180 #define IS_TOO_BIG_GT1(f) ((fabs(f)>1.0e+3)?1:0)
181 
182 void NE10_float_rng_limit_gt1_init (uint32_t seed)
183 {
184  NE10_float_rng_init_g (&__NE10_float_rng_limit , seed);
185 }
186 
187 float NE10_float_rng_limit_gt1_next()
188 {
189  float ret = 0.0f;
190 
191  do
192  {
193  ret = NE10_float_rng_next_g (&__NE10_float_rng_limit);
194  }
195  while (IS_TOO_SMALL_GT1 (ret) || IS_TOO_BIG_GT1 (ret));
196 
197  return ret;
198 }
199 
200 float NE10_float_rng_limit_gt1_max()
201 {
202  return NE10_float_rng_max_g (NULL);
203 }
NE10_float_rng_t
Definition: NE10_random.h:53
NE10_rng_t
Definition: NE10_random.h:45