local export = {}
local format = string.format
local is_integer -- defined as export.is_integer below
local is_positive_integer -- defined as export.is_positive_integer below
local log = math.log
local log10 = math.log10
local select = select
local tonumber = tonumber
local tostring = tostring
local type = type
--[==[
Returns true if the given value is a finite real number, or false if not.]==]
function export.is_finite_real_number(n)
return n and type(n) == "number" and n - n == 0 -- INF, -INF and NAN fail here.
end
--[==[
Returns true if the given value is an integer, or false if not.]==]
function export.is_integer(n)
return n and type(n) == "number" and n % 1 == 0 -- INF, -INF and NAN also fail here.
end
is_integer = export.is_integer
--[==[
Returns true if the given value is a positive integer (or zero if the `include_0` flag is set), or false if not.]==]
function export.is_positive_integer(n, include_0)
return is_integer(n) and (n > 0 or include_0 and n == 0) or false
end
is_positive_integer = export.is_positive_integer
--[==[
Converts a decimal number to hexadecimal.]==]
function export.to_hex(dec)
dec = tonumber(dec)
if not is_positive_integer(dec, true) then
error("must be an integer greater than or equal to 0")
elseif dec >= 18446744073709551616 then
error("integer overflow") -- string.format returns "0" for numbers >= 2^64
end
return format("%X", dec)
end
--[==[
Returns the base-10 logarithm of `x`.
Should be used instead of `math.log10`, which is deprecated and may stop working
if Scribunto is updated to a more recent Lua version.]==]
function export.log10(x)
if log10 == nil then
if log(10, 10) == 1 then -- Lua 5.2
function log10(x)
return log(x, 10)
end
else
function log10(x)
return log(x) * 0.43429448190325182765112891891660508229439700580367 -- log10(e)
end
end
end
export.log10 = log10
end
export.log10() -- Sets the actual returned function. Structured like this so that module docuemntation works.
--[==[
Returns the greatest common divisor.]==]
function export.gcd(n, q, ...)
if not is_integer(n) then
local type_n = type(n)
error(format(
"bad argument #%d to 'gcd' (integer expected, got %s)",
1, type_n == "number" and tostring(n) or type_n
), 2)
end
local args_n, integers = select("#", q, ...)
-- q is always counted in args_n, but if it's nil there's nothing left to do.
if args_n == 1 and q == nil then
args_n = 0
end
-- Compute p_1 = gcd(n_1, n_2), p_2 = gcd(p_1, n_3), ... i.e. compute GCD by Euclid's algorithm for the current result and the next number.
for i = 1, args_n do
if not is_integer(q) then
local type_q = type(q)
error(format(
"bad argument #%d to 'gcd' (integer expected, got %s)",
i + 1, type_q == "number" and tostring(q) or type_q
), 2)
elseif n ~= 1 then -- If n is 1, validate remaining inputs.
-- GCD of two integers n, q with Euclid's algorithm.
while q ~= 0 do
n, q = q, n % q
end
end
if i == 1 then
q = ...
elseif i < args_n then
-- Only create a table if absolutely necessary, as it's inefficient.
if i == 2 then
integers = {...}
end
q = integers[i]
end
end
return n < 0 and -n or n
end
--[==[
Returns the least common multiple.]==]
function export.lcm(n, q, ...)
if not is_integer(n) then
local type_n = type(n)
error(format(
"bad argument #%d to 'lcm' (integer expected, got %s)",
1, type_n == "number" and tostring(n) or type_n
), 2)
end
local args_n, integers = select("#", q, ...)
-- q is always counted in args_n, but if it's nil there's nothing left to do.
if args_n == 1 and q == nil then
args_n = 0
end
-- Compute the product of all inputs as p and GCD as n.
for i = 1, args_n do
if not is_integer(q) then
local type_q = type(q)
error(format(
"bad argument #%d to 'lcm' (integer expected, got %s)",
i + 1, type_q == "number" and tostring(q) or type_q
), 2)
elseif n ~= 0 then -- If n is 0, validate remaining inputs.
-- Compute the product.
local p = n * q
-- GCD of two integers n, q with Euclid's algorithm.
while q ~= 0 do
n, q = q, n % q
end
-- Divide product by the GCD to get new LCM.
n = p / n
end
if i == 1 then
q = ...
elseif i < args_n then
-- Only create a table if absolutely necessary, as it's inefficient.
if i == 2 then
integers = {...}
end
q = integers[i]
end
end
return n < 0 and -n or n
end
return export