24
24
#include "ext/standard/php_array.h"
25
25
#include "ext/standard/php_string.h"
26
26
27
+ #include "Zend/zend_enum.h"
27
28
#include "Zend/zend_exceptions.h"
28
29
29
30
static inline void randomizer_common_init (php_random_randomizer * randomizer , zend_object * engine_object ) {
@@ -160,6 +161,58 @@ static uint64_t getFloat_ceilint(double a, double b, double g)
160
161
return (s != si ) ? (uint64_t )si : (uint64_t )si + (e > 0 );
161
162
}
162
163
164
+ static double getFloat_closed_open (const php_random_algo * algo , php_random_status * status , double min , double max )
165
+ {
166
+ double g = getFloat_gamma (min , max );
167
+ uint64_t hi = getFloat_ceilint (min , max , g );
168
+ uint64_t k = algo -> range (status , 1 , hi );
169
+
170
+ if (fabs (min ) <= fabs (max )) {
171
+ return k == hi ? min : max - k * g ;
172
+ } else {
173
+ return min + (k - 1 ) * g ;
174
+ }
175
+ }
176
+
177
+ static double getFloat_closed_closed (const php_random_algo * algo , php_random_status * status , double min , double max )
178
+ {
179
+ double g = getFloat_gamma (min , max );
180
+ uint64_t hi = getFloat_ceilint (min , max , g );
181
+ uint64_t k = algo -> range (status , 0 , hi );
182
+
183
+ if (fabs (min ) <= fabs (max )) {
184
+ return k == hi ? min : max - k * g ;
185
+ } else {
186
+ return k == hi ? max : min + k * g ;
187
+ }
188
+ }
189
+
190
+ static double getFloat_open_closed (const php_random_algo * algo , php_random_status * status , double min , double max )
191
+ {
192
+ double g = getFloat_gamma (min , max );
193
+ uint64_t hi = getFloat_ceilint (min , max , g );
194
+ uint64_t k = algo -> range (status , 0 , hi - 1 );
195
+
196
+ if (fabs (min ) <= fabs (max )) {
197
+ return max - k * g ;
198
+ } else {
199
+ return k == (hi - 1 ) ? max : min + (k + 1 ) * g ;
200
+ }
201
+ }
202
+
203
+ static double getFloat_open_open (const php_random_algo * algo , php_random_status * status , double min , double max )
204
+ {
205
+ double g = getFloat_gamma (min , max );
206
+ uint64_t hi = getFloat_ceilint (min , max , g );
207
+ uint64_t k = algo -> range (status , 1 , hi - 1 );
208
+
209
+ if (fabs (min ) <= fabs (max )) {
210
+ return max - k * g ;
211
+ } else {
212
+ return min + k * g ;
213
+ }
214
+ }
215
+
163
216
/* {{{ Generates a random float within [min, max).
164
217
*
165
218
* The algorithm used is the γ-section algorithm as published in:
@@ -172,30 +225,56 @@ PHP_METHOD(Random_Randomizer, getFloat)
172
225
{
173
226
php_random_randomizer * randomizer = Z_RANDOM_RANDOMIZER_P (ZEND_THIS );
174
227
double min , max ;
228
+ zend_object * bounds = NULL ;
229
+ zend_string * bounds_name = zend_string_init ("ClosedOpen" , strlen ("ClosedOpen" ), 1 );
175
230
176
- ZEND_PARSE_PARAMETERS_START (2 , 2 )
231
+ ZEND_PARSE_PARAMETERS_START (2 , 3 )
177
232
Z_PARAM_DOUBLE (min )
178
233
Z_PARAM_DOUBLE (max )
234
+ Z_PARAM_OPTIONAL
235
+ Z_PARAM_OBJ_OF_CLASS (bounds , random_ce_Random_IntervalBoundary );
179
236
ZEND_PARSE_PARAMETERS_END ();
180
237
181
238
#ifndef __STDC_IEC_559__
182
239
zend_throw_exception (random_ce_Random_RandomException , "The getFloat() method requires the underlying 'double' representation to be IEEE-754." , 0 );
183
240
RETURN_THROWS ();
184
241
#endif
185
242
186
- if (UNEXPECTED ( max < min ) ) {
187
- zend_argument_value_error ( 2 , "must be greater than or equal to argument #1 ($min)" );
188
- RETURN_THROWS ( );
243
+ if (bounds ) {
244
+ zval * case_name = zend_enum_fetch_case_name ( bounds );
245
+ bounds_name = Z_STR_P ( case_name );
189
246
}
247
+
248
+ if (zend_string_equals_literal (bounds_name , "ClosedOpen" )) {
249
+ if (UNEXPECTED (max <= min )) {
250
+ zend_argument_value_error (2 , "must be greater than argument #1 ($min)" );
251
+ RETURN_THROWS ();
252
+ }
190
253
191
- double g = getFloat_gamma (min , max );
192
- uint64_t hi = getFloat_ceilint (min , max , g );
193
- uint64_t k = randomizer -> algo -> range (randomizer -> status , 1 , hi );
254
+ RETURN_DOUBLE (getFloat_closed_open (randomizer -> algo , randomizer -> status , min , max ));
255
+ } else if (zend_string_equals_literal (bounds_name , "ClosedClosed" )) {
256
+ if (UNEXPECTED (max < min )) {
257
+ zend_argument_value_error (2 , "must be greater than or equal to argument #1 ($min)" );
258
+ RETURN_THROWS ();
259
+ }
194
260
195
- if (fabs (min ) <= fabs (max )) {
196
- RETURN_DOUBLE (k == hi ? min : max - k * g );
261
+ RETURN_DOUBLE (getFloat_closed_closed (randomizer -> algo , randomizer -> status , min , max ));
262
+ } else if (zend_string_equals_literal (bounds_name , "OpenClosed" )) {
263
+ if (UNEXPECTED (max <= min )) {
264
+ zend_argument_value_error (2 , "must be greater than argument #1 ($min)" );
265
+ RETURN_THROWS ();
266
+ }
267
+
268
+ RETURN_DOUBLE (getFloat_open_closed (randomizer -> algo , randomizer -> status , min , max ));
269
+ } else if (zend_string_equals_literal (bounds_name , "OpenOpen" )) {
270
+ if (UNEXPECTED (max <= min )) {
271
+ zend_argument_value_error (2 , "must be greater than argument #1 ($min)" );
272
+ RETURN_THROWS ();
273
+ }
274
+
275
+ RETURN_DOUBLE (getFloat_open_open (randomizer -> algo , randomizer -> status , min , max ));
197
276
} else {
198
- RETURN_DOUBLE ( min + ( k - 1 ) * g );
277
+ ZEND_UNREACHABLE ( );
199
278
}
200
279
}
201
280
/* }}} */
0 commit comments