-
Notifications
You must be signed in to change notification settings - Fork 7.8k
Add Randomizer::nextFloat() and Randomizer::getFloat() #9679
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
14 commits
Select commit
Hold shift + click to select a range
5017048
random: Add Randomizer::nextFloat()
TimWolla 404342b
random: Check that doubles are IEEE-754 in Randomizer::nextFloat()
TimWolla 8a31678
random: Add Randomizer::nextFloat() tests
TimWolla 918ef25
random: Add Randomizer::getFloat() implementing the y-section algorithm
TimWolla 9cb4291
random: Implement getFloat_gamma() optimization
TimWolla 63dc454
random: Add Random\IntervalBoundary
TimWolla 18f2ab8
random: Split the implementation of γ-section into its own file
TimWolla b80ecbb
random: Add tests for Randomizer::getFloat()
TimWolla a323cb0
random: Fix γ-section for 32-bit systems
TimWolla bd0bee4
random: Replace check for __STDC_IEC_559__ by compile-time check for …
TimWolla 69a0b8d
random: Drop nextFloat_spacing.phpt
TimWolla ed8049b
random: Optimize Randomizer::getFloat() implementation
TimWolla c51cf82
random: Reject non-finite parameters in Randomizer::getFloat()
TimWolla 1c3d997
random: Add NEWS/UPGRADING for Randomizer’s float functionality
TimWolla File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,4 @@ | ||
EXTENSION("random", "random.c", false /* never shared */, "/DZEND_ENABLE_STATIC_TSRMLS_CACHE=1"); | ||
PHP_RANDOM="yes"; | ||
ADD_SOURCES(configure_module_dirname, "engine_combinedlcg.c engine_mt19937.c engine_pcgoneseq128xslrr64.c engine_xoshiro256starstar.c engine_secure.c engine_user.c randomizer.c", "random"); | ||
ADD_SOURCES(configure_module_dirname, "engine_combinedlcg.c engine_mt19937.c engine_pcgoneseq128xslrr64.c engine_xoshiro256starstar.c engine_secure.c engine_user.c gammasection.c randomizer.c", "random"); | ||
PHP_INSTALL_HEADERS("ext/random", "php_random.h"); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
/* | ||
+----------------------------------------------------------------------+ | ||
| Copyright (c) The PHP Group | | ||
+----------------------------------------------------------------------+ | ||
| This source file is subject to version 3.01 of the PHP license, | | ||
| that is bundled with this package in the file LICENSE, and is | | ||
| available through the world-wide-web at the following url: | | ||
| https://www.php.net/license/3_01.txt | | ||
| If you did not receive a copy of the PHP license and are unable to | | ||
| obtain it through the world-wide-web, please send a note to | | ||
| [email protected] so we can mail you a copy immediately. | | ||
+----------------------------------------------------------------------+ | ||
| Authors: Tim Düsterhus <[email protected]> | | ||
| | | ||
| Based on code from: Frédéric Goualard | | ||
+----------------------------------------------------------------------+ | ||
*/ | ||
|
||
#ifdef HAVE_CONFIG_H | ||
# include "config.h" | ||
#endif | ||
|
||
#include "php.h" | ||
#include "php_random.h" | ||
#include <math.h> | ||
|
||
/* This file implements the γ-section algorithm as published in: | ||
* | ||
* Drawing Random Floating-Point Numbers from an Interval. Frédéric | ||
* Goualard, ACM Trans. Model. Comput. Simul., 32:3, 2022. | ||
* https://doi.org/10.1145/3503512 | ||
*/ | ||
|
||
static double gamma_low(double x) | ||
{ | ||
return x - nextafter(x, -DBL_MAX); | ||
} | ||
|
||
static double gamma_high(double x) | ||
{ | ||
return nextafter(x, DBL_MAX) - x; | ||
} | ||
|
||
static double gamma_max(double x, double y) | ||
{ | ||
return (fabs(x) > fabs(y)) ? gamma_high(x) : gamma_low(y); | ||
} | ||
|
||
static uint64_t ceilint(double a, double b, double g) | ||
{ | ||
double s = b / g - a / g; | ||
double e; | ||
|
||
if (fabs(a) <= fabs(b)) { | ||
e = -a / g - (s - b / g); | ||
} else { | ||
e = b / g - (s + a / g); | ||
} | ||
|
||
double si = ceil(s); | ||
|
||
return (s != si) ? (uint64_t)si : (uint64_t)si + (e > 0); | ||
} | ||
|
||
PHPAPI double php_random_gammasection_closed_open(const php_random_algo *algo, php_random_status *status, double min, double max) | ||
{ | ||
double g = gamma_max(min, max); | ||
uint64_t hi = ceilint(min, max, g); | ||
uint64_t k = 1 + php_random_range64(algo, status, hi - 1); /* [1, hi] */ | ||
|
||
if (fabs(min) <= fabs(max)) { | ||
return k == hi ? min : max - k * g; | ||
} else { | ||
return min + (k - 1) * g; | ||
} | ||
} | ||
|
||
PHPAPI double php_random_gammasection_closed_closed(const php_random_algo *algo, php_random_status *status, double min, double max) | ||
{ | ||
double g = gamma_max(min, max); | ||
uint64_t hi = ceilint(min, max, g); | ||
uint64_t k = php_random_range64(algo, status, hi); /* [0, hi] */ | ||
|
||
if (fabs(min) <= fabs(max)) { | ||
return k == hi ? min : max - k * g; | ||
} else { | ||
return k == hi ? max : min + k * g; | ||
} | ||
} | ||
|
||
PHPAPI double php_random_gammasection_open_closed(const php_random_algo *algo, php_random_status *status, double min, double max) | ||
{ | ||
double g = gamma_max(min, max); | ||
uint64_t hi = ceilint(min, max, g); | ||
uint64_t k = php_random_range64(algo, status, hi - 1); /* [0, hi - 1] */ | ||
|
||
if (fabs(min) <= fabs(max)) { | ||
return max - k * g; | ||
} else { | ||
return k == (hi - 1) ? max : min + (k + 1) * g; | ||
} | ||
} | ||
|
||
PHPAPI double php_random_gammasection_open_open(const php_random_algo *algo, php_random_status *status, double min, double max) | ||
{ | ||
double g = gamma_max(min, max); | ||
uint64_t hi = ceilint(min, max, g); | ||
uint64_t k = 1 + php_random_range64(algo, status, hi - 2); /* [1, hi - 1] */ | ||
|
||
if (fabs(min) <= fabs(max)) { | ||
return max - k * g; | ||
} else { | ||
return min + k * g; | ||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do these need exception handling since
php_random_range64
can throw, or does0
work out acceptably in the math and then the error will still be set in the global state?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would prefer that these APIs didn't throw, to be honest -- I like it when the C APIs can be used basically like regular C code without Zend Engine side effects getting in the way, but I'm not going to block the PR on it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@morrisonlevi
0 is a valid return value that may be returned by php_random_range64 in the happy path, so the result will be well-defined in the error path (even if not particularly random).
Depending on the algo (“the engine”) these functions may call into userland, thus needing to deal with Exceptions is unavoidable:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To clarify, though:
php_random_range64
will not throw, unless either the underlying algo throws, or the underlying algo is so horribly biased that it may not be called random (a number is rejected with < 50% chance, 50 rejections thus have a probability of < 2-50 which is less than 1 in a quadrillion).