Open
Description
Description
While playing around with Random\Randomizer::getFloat()
I noticed that it does return unexpected results in some extreme edge cases.
The following code:
<?php
$r = new \Random\Randomizer();
echo "\ninterval: (-5.0E-324, +5.0E-324)";
echo "\nexpected: float(0)\nactual: ";
var_dump($r->getFloat(-5.0E-324, +5.0E-324, \Random\IntervalBoundary::OpenOpen));
// float(-5.0E-324)
echo "\ninterval: (0.0, 1.0E-323)";
echo "\nexpected: float(5.0E-324)\nactual: ";
var_dump($r->getFloat(0.0, 1.0E-323, \Random\IntervalBoundary::OpenOpen));
// float(-5.0E-324)
echo "\ninterval: (5.0E-324, 1.5E-323)";
echo "\nexpected: float(1.0E-323)\nactual: ";
var_dump($r->getFloat(5.0E-324, 1.5E-323, \Random\IntervalBoundary::OpenOpen));
// float(1.5E-323)
echo "\ninterval: (0.0, 5.0E-324]";
echo "\nexpected: float(5.0E-324)\nactual: ";
var_dump($r->getFloat(0.0, 5.0E-324, \Random\IntervalBoundary::OpenClosed));
// float(0)
echo "\ninterval: (5.0E-324, 1.0E-323]";
echo "\nexpected: float(1.0E-323)\nactual: ";
var_dump($r->getFloat(5.0E-324, 1.0E-323, \Random\IntervalBoundary::OpenClosed));
// float(0)
Resulted in this output:
interval: (-5.0E-324, +5.0E-324)
expected: float(0)
actual: float(-5.0E-324)
interval: (0.0, 1.0E-323)
expected: float(5.0E-324)
actual: float(-5.0E-324)
interval: (5.0E-324, 1.5E-323)
expected: float(1.0E-323)
actual: float(1.5E-323)
interval: (0.0, 5.0E-324]
expected: float(5.0E-324)
actual: float(0)
interval: (5.0E-324, 1.0E-323]
expected: float(1.0E-323)
actual: float(0)
These are all cases where only a single float value is possible to be drawn, but the results are consistently wrong and up to two values apart from the correct result.
Slightly larger ranges also seem to be affected by this. In the following example the floats 1.0E-323 and 1.5E-323 get skipped but the floats 3.5E-323 and 4.0E-323 get included even though they are outside the boundary.
var_dump($r->getFloat(5.0E-324, 3.0E-323, \Random\IntervalBoundary::ClosedClosed));
// Should draw one of: 5.0E-324, 1.0E-323, 1.5E-323, 2.0E-323, 2.5E-323, 3.0E-323
// Insteads draws from: 5.0E-324, 2.0E-323, 2.5E-323, 3.0E-323, 3.5E-323, 4.0E-323
For reference here are the HEX representations (64bit big endian) of the used floats:
-5.0E-324: 8000000000000001
5.0E-324: 0000000000000001
1.0E-323: 0000000000000002
1.5E-323: 0000000000000003
2.0E-323: 0000000000000004
2.5E-323: 0000000000000005
3.0E-323: 0000000000000006
3.5E-323: 0000000000000007
4.0E-323: 0000000000000008
PHP Version
PHP 8.3.6
Operating System
macOS 14.4.1 (23E224)