Various mathematical functions.
function export.is_finite_real_number(n)
Returns true if the given value is a finite real number, or false if not.
function export.is_integer(n)
Returns true if the given value is an integer, or false if not.
function export.is_positive_integer(n, include_0)
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.log10(x)
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.to_hex(dec)
Converts a decimal number to hexadecimal.
function export.gcd(n, ...)
Returns the greatest common divisor.
function export.lcm(n, ...)
Returns the least common multiple.
local export = {}
local format = string.format
local is_integer -- defined as export.is_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
--[==[
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.
local function integer_error(x, param, func_name)
local type_x = type(x)
error(format(
"bad argument #%d to '%s' (integer expected, got %s)",
param, func_name, type_x == "number" and tostring(x) or type_x
), 3)
end
--[==[
Converts a decimal number to hexadecimal.]==]
function export.to_hex(dec)
dec = tonumber(dec) or dec
if not is_integer(dec, true) then
integer_error(dec, 1, "to_hex")
end
local neg = dec < 0
if neg then
dec = -dec
end
-- Inputs >= 2^64 cause string.format to return "0".
if dec >= 18446744073709551616 then
error("integer overflow in 'to_hex': cannot convert inputs with a magnitude greater than or equal to 2^64 (18446744073709551616)", 2)
end
-- string.format treats hex numbers as unsigned, so any sign must be added manually.
return format("%s%X", neg and "-" or "", dec)
end
--[==[
Returns the greatest common divisor.]==]
function export.gcd(n, ...)
n = tonumber(n) or n
if not is_integer(n) then
integer_error(n, 1, "gcd")
end
local q, args_len, integers = ..., select("#", ...)
-- 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 = 2, args_len + 1 do
q = tonumber(q) or q
if not is_integer(q) then
integer_error(q, i, "gcd")
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 <= args_len then
-- Only create a table if absolutely necessary, as it's inefficient.
if i == 2 then
integers = {...}
end
q = integers
end
end
return n < 0 and -n or n
end
--[==[
Returns the least common multiple.]==]
function export.lcm(n, ...)
n = tonumber(n) or n
if not is_integer(n) then
integer_error(n, 1, "lcm")
end
local q, args_len, integers = ..., select("#", ...)
-- Compute the product of all inputs as p and GCD as n.
for i = 2, args_len + 1 do
q = tonumber(q) or q
if not is_integer(q) then
integer_error(q, i, "lcm")
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 <= args_len then
-- Only create a table if absolutely necessary, as it's inefficient.
if i == 2 then
integers = {...}
end
q = integers
end
end
return n < 0 and -n or n
end
return export