Skip to content

Commit 54bf451

Browse files
committed
[k2] implement random_int
1 parent 7335ee2 commit 54bf451

3 files changed

Lines changed: 55 additions & 2 deletions

File tree

builtin-functions/kphp-light/stdlib/math-functions.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,8 @@ function lcg_value() ::: float;
166166

167167
function random_bytes($length ::: int) ::: string | false;
168168

169+
function random_int($l ::: int, $r ::: int) ::: int | false;
170+
169171
/** @kphp-extern-func-info interruptible */
170172
function uniqid ($prefix ::: string = '', $more_entropy ::: bool = false) ::: string;
171173

@@ -185,5 +187,3 @@ define('PHP_ROUND_HALF_DOWN', 123423144);
185187
define('PHP_ROUND_HALF_EVEN', 123423145);
186188
define('PHP_ROUND_HALF_ODD', 123423146);
187189

188-
/** @kphp-extern-func-info stub generation-required */
189-
function random_int($l ::: int, $r ::: int) ::: int | false;

runtime-light/stdlib/math/random-functions.h

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
#include <algorithm>
88
#include <array>
9+
#include <bit>
910
#include <chrono>
1011
#include <cstddef>
1112
#include <cstdint>
@@ -25,6 +26,7 @@
2526
#include "runtime-common/stdlib/math/random-functions.h"
2627
#include "runtime-light/coroutine/task.h"
2728
#include "runtime-light/k2-platform/k2-api.h"
29+
#include "runtime-light/stdlib/diagnostics/logs.h"
2830
#include "runtime-light/stdlib/math/random-state.h"
2931
#include "runtime-light/stdlib/system/system-functions.h"
3032

@@ -157,6 +159,48 @@ inline Optional<string> f$random_bytes(int64_t length) noexcept {
157159
return str;
158160
}
159161

162+
inline Optional<int64_t> f$random_int(int64_t min, int64_t max) noexcept {
163+
if (min > max) [[unlikely]] {
164+
kphp::log::warning("argument #1 ($min) must be less than or equal to argument #2 ($max)");
165+
return false;
166+
}
167+
168+
if (min == max) {
169+
return min;
170+
}
171+
172+
auto umax{static_cast<uint64_t>(max) - static_cast<uint64_t>(min)};
173+
174+
uint64_t trial{};
175+
if (random_impl_::secure_rand_buf(std::addressof(trial), sizeof(trial)) == -1) [[unlikely]] {
176+
kphp::log::warning("source of randomness cannot be found");
177+
return false;
178+
}
179+
180+
// special case where no modulus is required
181+
if (umax == std::numeric_limits<uint64_t>::max()) {
182+
return static_cast<int64_t>(trial);
183+
}
184+
185+
++umax; // increment the max so the range is inclusive of max
186+
187+
// powers of two are not biased
188+
if (!std::has_single_bit(umax)) {
189+
// ceiling under which UINT64_MAX % max == 0
190+
const auto limit{std::numeric_limits<uint64_t>::max() - (std::numeric_limits<uint64_t>::max() % umax) - 1};
191+
192+
// discard numbers over the limit to avoid modulo bias
193+
while (trial > limit) {
194+
if (random_impl_::secure_rand_buf(std::addressof(trial), sizeof(trial)) == -1) [[unlikely]] {
195+
kphp::log::warning("source of randomness cannot be found");
196+
return false;
197+
}
198+
}
199+
}
200+
201+
return min + static_cast<int64_t>(trial % umax);
202+
}
203+
160204
inline kphp::coro::task<string> f$uniqid(string prefix = string{}, bool more_entropy = false) noexcept {
161205
if (!more_entropy) {
162206
co_await f$usleep(1);

tests/phpt/dl/386_random_int.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,15 @@
22
<?php
33

44
function test_random_int() {
5+
$x = random_int(-1, 0);
6+
var_dump($x >= -1 && $x <= 0);
7+
8+
$x = random_int(-1, 1);
9+
var_dump($x >= -1 && $x <= 1);
10+
11+
$x = random_int(0, 1);
12+
var_dump($x >= 0 && $x <= 1);
13+
514
$x = random_int(100, 500);
615
var_dump($x >= 100 && $x <= 500);
716

0 commit comments

Comments
 (0)