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 щоб отримати потрібні поведінкові властивості.

Дивіться також