Hi

On 12/20/22 09:15, Hans Henrik Bergan wrote:
btw while we're on the topic, does anyone know if this function gives
biased results/is-safe or not? i honestly don't know:
function random_float(float $min, float $max): float
{
     if ($min > $max) throw new \InvalidArgumentException("min must be
less than max");
     if ($min === $max) return $min;
     return $min + random_int(0, PHP_INT_MAX) / PHP_INT_MAX * ($max - $min);
}



To give a clear answer on this one:

For a full evaluation the reader lacks information: What is this function supposed to do? For floats, the definition of the boundaries matter (that's why it's a parameter for Randomizer::getFloat()). Your function is implemented on the closed interval [0, 1] (i.e. both including 0 and 1). As mentioned in my email a few minutes ago, I consider the ClosedClosed behavior to not be the most useful in the general case, but in your case it might be the correct behavior.

Nonetheless, the function is definitely broken:

1. A IEEE 754 double precision float as used by PHP only has 53 Bits of precision, but you generate a random 64 Bit integer. Thus rounding will occur and might cause some values to be returned more often than other.

To improve the function you should only generate 53 Bits of randomness (i.e. use 2**53 as the divisor and either 2**53-1 or 2**53 as the dividend).

2. Using the (min + rand * (max - min)) construction will generate biased results (see also my other email).

PHP 8.3's Randomizer::getFloat() method uses the γ-section algorithm proposed by Prof. Goualard to generate unbiased results for arbitrary ranges. This algorithm cannot reasonably be implemented in userland, because the necessary "building blocks" (obtaining the next/previous float for a given float) are not available for userland code. The best you can do in PHP 8.2 userland is what Randomizer::nextFloat() does.

TLDR: Yes, the function is broken.

Best regards
Tim Düsterhus

--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: https://www.php.net/unsub.php

Reply via email to