mercredi 8 juin 2022

What's the most efficient way of randomly picking a floating number within a specific range?

I have a random number generator function to generate both an integer and floating point number within a specific range. My only problem is with float wherein I simply used range() to generate the range of possible values that can be picked by mt_rand() or random_int(). One can only imagine the inefficiency of generating a range from -9.99999999999999 to 9.99999999999999.

Although I tried other approaches such as separating the integer part and the fractional part then generating them separately, removing the decimal point then generating from that range, but they all have their own complexities.

Is there a better way to randomly pick a floating number within a specific range?

PHP Code

function generateNumber(int|float $start = PHP_INT_MIN, int|float $end = PHP_INT_MAX, int|null $seed = null, bool $isInteger = true, bool $isCryptographic = false): int|float {
    $randFunction = ($isCryptographic === false ? 'mt_rand' : 'random_int');

    var_dump($randFunction);

    if ($isInteger === true) {
        $start = (int) $start;
        $end = (int) $end;

        if (!$isCryptographic && $seed !== null) mt_srand($seed);

        return $randFunction($start, $end);
    }

    $start = (float) $start;
    $end = (float) $end;

    $hasDecimalPoint = strrchr(haystack: (string) $start, needle: '.');
    $start = ($hasDecimalPoint ? $start : "{$start}.0");

    $hasDecimalPoint = strrchr(haystack: (string) $end, needle: '.');
    $end = ($hasDecimalPoint ? $end : "{$end}.0");

    $startFractionDigits = strlen(substr(strrchr(haystack: (string) $start, needle: '.'), offset: 1));
    $endFractionDigits = strlen(substr(strrchr(haystack: (string) $end, needle: '.'), offset: 1));

    var_dump($startFractionDigits);
    var_dump($endFractionDigits);

    $step = 10 ** -($startFractionDigits > $endFractionDigits ? $startFractionDigits : $endFractionDigits);
    $numberList = range($start, $end, $step);

    var_dump($step);
    print_r($numberList);

    if (!$isCryptographic && $seed !== null) mt_srand($seed);

    $min = 0;
    $max = count($numberList) - 1;
    $index = $randFunction($min, $max);

    return $numberList[$index];
}

var_dump(generateNumber(start: -1.18, end: -1.25, seed: null, isInteger: false, isCryptographic: false));

Sample Output:

string(7) "mt_rand"
int(2)
int(2)
float(0.01)
Array
(
    [0] => -1.18
    [1] => -1.19
    [2] => -1.2
    [3] => -1.21
    [4] => -1.22
    [5] => -1.23
    [6] => -1.24
    [7] => -1.25
)
float(-1.22)



Aucun commentaire:

Enregistrer un commentaire