Random\Randomizer::getFloat
(PHP 8 >= 8.3.0)
Random\Randomizer::getFloat — Отримує рівномірно обране число з плаваючою точкою
Опис
public Random\Randomizer::getFloat(float $min, float $max, Random\IntervalBoundary $boundary = Random\IntervalBoundary::ClosedOpen): float
Повертає рівномірно обране рівнорозподілене число з плаваючою точкою із запитаного інтервалу.
Через обмежену точність в повному обсязі речові (дійсні) числа вдається точно уявити як числа з плаваючою точкою. Якщо число неможливо уявити точно, воно округляється до найближчого точного значення. Крім сказаного, числа з точкою, що плаває, не однаково щільні по всьому числовому рядку. Оскільки перетворення чисел з плаваючою точкою проводяться з двійковою експонентою, відстань між двома сусідніми числами з плаваючою точкою подвоюється при кожному ступені двійки. Інакше кажучи: між значеннями 1.0
и2.0
існує така ж кількість представимих чисел з плаваючою точкою, як і між 2.0
и4.0
4.0
и8.0
8.0
и16.0
и т. д.
Тому довільна вибірка випадкового числа в межах запитаного інтервалу, наприклад, шляхом поділу двох цілих чисел іноді призводить до зміщеного розподілу. Необхідне округлення призведе до того, що одні числа з плаваючою точкою повертатимуться частіше, ніж інші, особливо в районі ступенів двійки, коли щільність чисел із плаваючою точкою зміниться.
МетодRandom\Randomizer::getFloat() реалізує алгоритм, який повертатиме рівномірно обране число з плаваючою точкою з максимально можливого набору точно представлених і рівнорозподілених чисел з плаваючою точкою в межах інтервалу. Відстань між вибираються числами з плаваючою точкою («розмір кроку») відповідає відстані між числами з плаваючою точкою з найменшою щільністю, тобто відстані між числами з плаваючою точкою на межі інтервалу з великим абсолютним значенням. Тобто не всім представленим числам з плаваючою точкою в межах цього інтервалу можна повертатися, якщо інтервал перетинає один або кілька ступенів двійки. Крок почнеться з межі інтервалу з великим абсолютним значенням, щоб гарантувати, що кроки збігаються з точно представленими числами з точкою, що плаває.
Межі закритих інтервалів завжди будуть включені в набір плаваючих значень, що вибираються. Так, якщо розмір інтервалу не кратаний розміру кроку і межа з меншим абсолютним значенням - це замкнута межа, відстань між цією кордоном і найближчим до неї обраним числом з плаваючою точкою буде менше розміру кроку.
Застереження
Постобработка повернених чисел з плаваючою точкою, швидше за все, порушить рівномірний рівнорозподіл, оскільки проміжні плаваючі значення математичної операції неявно округляються. Запрошений інтервал повинен якомога точніше відповідати потрібному інтервалу, а округлення має виконуватися лише як явна операція безпосередньо перед відображенням вибраного числа користувача.
Пояснення алгоритму з прикладами значень
Щоб навести приклад роботи алгоритму, розглянемо уявлення з плаваючою точкою, в якому вибрано 3-бітну мантису. Це уявлення здатне представляти 8 різних значень з плаваючою точкою між послідовними ступенями двох. Тобто між 1.0
и2.0
всі кроки розміром 0.125
точно уявні і між 2.0
и4.0
всі кроки розміром 0.25
точно уявні. У PHP для роботи з числами з плаваючою точкою обрана 52-бітна мантиса і PHP може представляти 252 різних значення між кожним ступенем двійки. Це означає, що
1.0
1.125
1.25
1.375
1.5
1.625
1.75
1.875
2.0
2.25
2.5
2.75
3.0
3.25
3.5
3.75
4.0
- точно представлені числа з плаваючою точкою між 1.0
и4.0
Тепер уявіть, що здійснено виклик $randomizer->getFloat(1.625, 2.5, IntervalBoundary::ClosedOpen)
, т. е. запитано випадкове число з плаваючою точкою, яке починається з 1.625
і закінчується 2.5
(Не включаючи останнє). Алгоритм спочатку визначає розмір кроку на кордоні з великим абсолютним значенням (2.5
). Розмір кроку на цьому кордоні дорівнює 0.25
Зверніть увагу, що розмір запитаного інтервалу. 0.875
, що не можна назвати точним кратним 0.25
. Якби алгоритм почав переходити на нижню межу 1.625
, воно зіткнулося б зі значенням 2.125
, який не зовсім уявимо і піддаватиметься неявному округленню. Тому алгоритм починає роботу з верхнього кордону.2.5
. Доступні значення:
2.25
2.0
1.75
1.625
Значение2.5
не включається, оскільки верхня межа інтервалу, що запитує, — відкритий кордон. Значення 1.625
включено, навіть незважаючи на те, що його відстань до найближчого значення 1.75
- це 0.125
, який менший за певний розмір кроку, що дорівнює 0.25
. Причина в тому, що інтервал, що запитає, закривається на нижньому кордоні (1.625
) та закриті кордони завжди включені.
Нарешті, алгоритм рівномірно вибирає одне з чотирьох значень, що вибираються випадковим чином і повертає його.
Чому розподіл двох цілих чисел не працює
У попередньому прикладі між кожним подинтервалом є вісім представимих чисел з плаваючою точкою, розділених ступенем двійки. Щоб проілюструвати, чому поділ двох цілих чисел не працює для створення випадкового числа з плаваючою точкою, припустимо, що у відкритому правому інтервалі від 0.0
до1.0
(не включаючи останнє) є 16 рівнорозподілених чисел із плаваючою комою. Половина з них - це вісім точно уявних значень між від 0.5
до1.0
, інша половина - це значення між 0.0
и1.0
з розміром кроку 0.0625
. Їх можна легко згенерувати, розділивши випадкове ціле число від до15
на16
, щоб отримати одне із значень:
0.0
0.0625
0.125
0.1875
0.25
0.3125
0.375
0.4375
0.5
0.5625
0.625
0.6875
0.75
0.8125
0.875
0.9375
Це випадкове число з плаваючою точкою можна масштабувати до інтервалу з відкритим інтервалом праворуч від 1.625
до2.75
(не включаючи останнє), помноживши його на розмір інтервалу (0.875
) і додавши мінімум 1.625
. Це так зване афінне перетворення призведе до значень:
1.625
округляється до1.625
1.679
округляється до1.625
1.734
округляється до1.75
1.789
округляється до1.75
1.843
округляється до1.875
1.898
округляється до1.875
1.953
округляється до2.0
2.007
округляється до2.0
2.062
округляється до2.0
2.117
округляється до2.0
2.171
округляється до2.25
2.226
округляється до2.25
2.281
округляється до2.25
2.335
округляється до2.25
2.390
округляється до2.5
2.445
округляється до2.5
Зверніть увагу, як буде повернуто верхній кордон 2.5
незважаючи на те, що це відкритий кордон і, отже, виключено. Також зверніть увагу, що ймовірність повертання значень 2.0
и2.25
удвічі вище, ніж в інших значень.
Список параметрів
min
Нижня межа інтервалу.
max
Верхня межа інтервалу.
boundary
Вказує, чи є межі інтервалу можливими значеннями, що повертаються.
Значення, що повертаються
Повертає рівномірно обране рівнорозподілене число з плаваючою точкою з інтервалу, заданого параметрами min
max
иboundary
. Можливі значення, що повертаються min
иmax
зависят от значения параметраboundary
Помилки
- Если значение
min
- Не кінцеве число (як це визначає функціяis_finite()), буде викинуто виняток ValueError - Если значение параметра
max
- Не кінцеве число (як це визначає функціяis_finite()), буде викинуто виняток ValueError - Якщо вибраний інтервал не містить значень, буде викинуто винятокValueError
- Будь-які Throwable, що викидаються методомRandom\Engine::generate()базового
Random\Randomizer::$engine
Приклади
Приклад #1 Приклад использования методаRandom\Randomizer::getFloat()****
Loading...
Висновок наведеного прикладу буде схожим на:
Широта: +69.244304 Долгота: -53.548951
Примітки
Зауваження :
Цей метод реалізує алгоритм γ-секції, опублікований у статті » Drawing Random Floating-Point Numbers from an Interval. Frédéric Goualard, ACM Trans. Model. Comput. Simul., 32:3, 2022 щоб отримати потрібні поведінкові властивості.
Дивіться також
- Random\Randomizer::nextFloat() - Отримує число з точкою, що плаває, з відкритого праворуч інтервалу[
- Random\Randomizer::getInt() - Отримує рівномірно обране ціле число