Skip to content

Commit a4f8a42

Browse files
committed
c
1 parent d25f8b5 commit a4f8a42

File tree

2 files changed

+60
-0
lines changed

2 files changed

+60
-0
lines changed

lua/commons/num.lua

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,13 @@ M.le = function(a, b, rel_tol, abs_tol)
7979
return M.lt(a, b, rel_tol, abs_tol) or M.eq(a, b, rel_tol, abs_tol)
8080
end
8181

82+
--- @param a integer
83+
--- @param b integer
84+
--- @return integer
85+
M.mod = function(a, b)
86+
return math.floor(math.fmod(a, b))
87+
end
88+
8289
--- @param value number
8390
--- @param left number? lower bound, by default INT32_MIN
8491
--- @param right number? upper bound, by default INT32_MAX
@@ -132,4 +139,34 @@ M.max = function(f, a, ...)
132139
return maximal_item, maximal_index
133140
end
134141

142+
-- Drop-in 32-bit random replacement of `math.random`.
143+
--- @param m integer?
144+
--- @param n integer?
145+
--- @return number
146+
M.random = function(m, n)
147+
local uv = vim.uv or vim.loop
148+
local rand_result, rand_err = uv.random(4)
149+
assert(rand_result ~= nil, rand_err)
150+
151+
local bytes = {
152+
string.byte(rand_result --[[@as string]], 1, -1),
153+
}
154+
local total = 0
155+
for _, b in ipairs(bytes) do
156+
total = M.mod(total * 256 + b, M.INT32_MAX)
157+
end
158+
if m == nil and n == nil then
159+
return total / M.INT32_MAX
160+
elseif m ~= nil and n == nil then
161+
assert(type(m) == "number")
162+
assert(m >= 1)
163+
return M.mod(total, m) + 1
164+
else
165+
assert(type(m) == "number")
166+
assert(type(n) == "number")
167+
assert(n >= m)
168+
return M.mod(total, n - m + 1) + m
169+
end
170+
end
171+
135172
return M

spec/commons/num_spec.lua

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,5 +115,28 @@ describe("commons.num", function()
115115
assert_false(ok)
116116
assert_eq(num.min(string.len, "a"), "a")
117117
end)
118+
it("mod", function()
119+
assert_eq(num.mod(2, 7), 2)
120+
assert_eq(num.mod(10, 7), 3)
121+
assert_eq(num.mod(10, 1), 0)
122+
assert_eq(num.mod(7, 6), 1)
123+
end)
124+
it("random", function()
125+
for i = 1, 50 do
126+
local actual1 = num.random()
127+
print(string.format("random-1(%s):%s\n", vim.inspect(type(actual1)), vim.inspect(actual1)))
128+
assert_true(actual1 >= 0 and actual1 < 1)
129+
end
130+
for i = 1, 50 do
131+
local actual2 = num.random(10)
132+
print(string.format("random-2(%s):%s\n", vim.inspect(type(actual2)), vim.inspect(actual2)))
133+
assert_true(actual2 >= 1 and actual2 <= 10)
134+
end
135+
for i = 1, 50 do
136+
local actual3 = num.random(10, 100)
137+
print(string.format("random-3(%s):%s\n", vim.inspect(type(actual3)), vim.inspect(actual3)))
138+
assert_true(actual3 >= 10 and actual3 <= 100)
139+
end
140+
end)
118141
end)
119142
end)

0 commit comments

Comments
 (0)