@@ -88,27 +88,6 @@ PHP_METHOD(Random_Randomizer, __construct)
88
88
}
89
89
/* }}} */
90
90
91
- /* {{{ Generate positive random number */
92
- PHP_METHOD (Random_Randomizer , nextInt )
93
- {
94
- php_random_randomizer * randomizer = Z_RANDOM_RANDOMIZER_P (ZEND_THIS );
95
- uint64_t result ;
96
-
97
- ZEND_PARSE_PARAMETERS_NONE ();
98
-
99
- result = randomizer -> algo -> generate (randomizer -> status );
100
- if (EG (exception )) {
101
- RETURN_THROWS ();
102
- }
103
- if (randomizer -> status -> last_generated_size > sizeof (zend_long )) {
104
- zend_throw_exception (random_ce_Random_RandomException , "Generated value exceeds size of int" , 0 );
105
- RETURN_THROWS ();
106
- }
107
-
108
- RETURN_LONG ((zend_long ) (result >> 1 ));
109
- }
110
- /* }}} */
111
-
112
91
/* {{{ Generate a float in [0, 1) */
113
92
PHP_METHOD (Random_Randomizer , nextFloat )
114
93
{
@@ -150,6 +129,101 @@ PHP_METHOD(Random_Randomizer, nextFloat)
150
129
}
151
130
/* }}} */
152
131
132
+ static double getFloat_gamma_low (double x )
133
+ {
134
+ return x - nextdown (x );
135
+ }
136
+
137
+ static double getFloat_gamma_high (double x )
138
+ {
139
+ return nextup (x ) - x ;
140
+ }
141
+
142
+ static double getFloat_gamma (double x , double y )
143
+ {
144
+ double high = getFloat_gamma_high (x );
145
+ double low = getFloat_gamma_low (y );
146
+
147
+ return high > low ? high : low ;
148
+ }
149
+
150
+ static uint64_t getFloat_ceilint (double a , double b , double g )
151
+ {
152
+ double s = b / g - a / g ;
153
+ double e ;
154
+
155
+ if (fabs (a ) <= fabs (b )) {
156
+ e = - a / g - (s - b / g );
157
+ } else {
158
+ e = b / g - (s + a / g );
159
+ }
160
+
161
+ double si = ceil (s );
162
+
163
+ return (s != si ) ? (uint64_t )si : (uint64_t )si + (e > 0 );
164
+ }
165
+
166
+ /* {{{ Generates a random float within [min, max).
167
+ *
168
+ * The algorithm used is the γ-section algorithm as published in:
169
+ *
170
+ * Drawing Random Floating-Point Numbers from an Interval. Frédéric
171
+ * Goualard, ACM Trans. Model. Comput. Simul., 32:3, 2022.
172
+ * https://doi.org/10.1145/3503512
173
+ */
174
+ PHP_METHOD (Random_Randomizer , getFloat )
175
+ {
176
+ php_random_randomizer * randomizer = Z_RANDOM_RANDOMIZER_P (ZEND_THIS );
177
+ double min , max ;
178
+
179
+ ZEND_PARSE_PARAMETERS_START (2 , 2 )
180
+ Z_PARAM_DOUBLE (min )
181
+ Z_PARAM_DOUBLE (max )
182
+ ZEND_PARSE_PARAMETERS_END ();
183
+
184
+ #ifndef __STDC_IEC_559__
185
+ zend_throw_exception (random_ce_Random_RandomException , "The getFloat() method requires the underlying 'double' representation to be IEEE-754." , 0 );
186
+ RETURN_THROWS ();
187
+ #endif
188
+
189
+ if (UNEXPECTED (max < min )) {
190
+ zend_argument_value_error (2 , "must be greater than or equal to argument #1 ($min)" );
191
+ RETURN_THROWS ();
192
+ }
193
+
194
+ double g = getFloat_gamma (min , max );
195
+ uint64_t hi = getFloat_ceilint (min , max , g );
196
+ uint64_t k = randomizer -> algo -> range (randomizer -> status , 1 , hi );
197
+
198
+ if (fabs (min ) <= fabs (max )) {
199
+ RETURN_DOUBLE (k == hi ? min : max - k * g );
200
+ } else {
201
+ RETURN_DOUBLE (min + (k - 1 ) * g );
202
+ }
203
+ }
204
+ /* }}} */
205
+
206
+ /* {{{ Generate positive random number */
207
+ PHP_METHOD (Random_Randomizer , nextInt )
208
+ {
209
+ php_random_randomizer * randomizer = Z_RANDOM_RANDOMIZER_P (ZEND_THIS );
210
+ uint64_t result ;
211
+
212
+ ZEND_PARSE_PARAMETERS_NONE ();
213
+
214
+ result = randomizer -> algo -> generate (randomizer -> status );
215
+ if (EG (exception )) {
216
+ RETURN_THROWS ();
217
+ }
218
+ if (randomizer -> status -> last_generated_size > sizeof (zend_long )) {
219
+ zend_throw_exception (random_ce_Random_RandomException , "Generated value exceeds size of int" , 0 );
220
+ RETURN_THROWS ();
221
+ }
222
+
223
+ RETURN_LONG ((zend_long ) (result >> 1 ));
224
+ }
225
+ /* }}} */
226
+
153
227
/* {{{ Generate random number in range */
154
228
PHP_METHOD (Random_Randomizer , getInt )
155
229
{
0 commit comments