Module:math - Wiktionary, the free dictionary
- The following documentation is located at Module:math/documentation. [edit]
- Useful links: subpage list • links • transclusions • testcases • sandbox
Various mathematical functions.
Detailed documentation
export.tonumber_extended
function export.tonumber_extended(x, base, finite_real, no_prefix)
An extended version of tonumber()
, which attempts to convert x
to a number. Like tonumber()
, it will convert from base 10 by default, and the optional parameter base
can be used to specify a different base between 2 and 36, with the letters A-Z
(case-insensitive) representing additional digits beyond 0-9
. When strings contain hexadecimal notation (e.g. "0x100"
), base 16 is used as the default instead, but this is overridden if base
is set to anything other than 16.
This function differs from tonumber()
in the following ways:
- If
finite_real
is set, then the function will only return finite real numbers; inputs which would normally produce ±infinity or NaN will instead producenil
. - If
no_prefix
is set, then strings which start with"0x"
will not be interpreted as containing hexadecimal notation, resulting innil
. - If
base
is explicitly set to10
, then strings in hexadecimal notation will always returnnil
. This fixes a bug intonumber()
, which treatsbase=10
the same asbase
being unset, causing base 16 to be used ifx
contains hexadecimal notation (e.g.tonumber("0x10", 10)
returns16
, whereastonumber_extended("0x10", 10)
returnsnil
).
export.is_finite_real_number
function export.is_finite_real_number(x)
Returns true
if x
is a finite real number, or false
if not. If x
is a string, it will not be coerced to a number before this check is performed.
export.is_integer
function export.is_integer(x)
Returns true
if x
is an integer, or false
if not. If x
is a string, it will not be coerced to a number before this check is performed.
export.is_positive_integer
function export.is_positive_integer(x, include_0)
Returns true
if x
is a positive integer (or zero if the include_0
flag is set), or false
if not. If x
is a string, it will not be coerced to a number before this check is performed.
export.log10
function export.log10(x)
Returns the base-10 logarithm of x
.
This function should be used instead of math.log10
, which is deprecated and may stop working if Scribunto is updated to a more recent Lua version.
export.to_hex
function export.to_hex(dec, include_prefix)
Converts a decimal number to hexadecimal. If include_prefix
is set, the returned number will include the 0x prefix.
export.gcd
function export.gcd(x, ...)
Returns the greatest common divisor of an arbitrary number of input numbers.
export.lcm
function export.lcm(x, ...)
Returns the least common multiple of an arbitrary number of input numbers.
local export = {} local format = string.format local is_integer -- defined as export.is_integer below local match = string.match local select = select local tonumber = tonumber local tostring = tostring local type = type --[==[ An extended version of {tonumber()}, which attempts to convert `x` to a number. Like {tonumber()}, it will convert from base 10 by default, and the optional parameter `base` can be used to specify a different base between 2 and 36, with the letters {A-Z} (case-insensitive) representing additional digits beyond {0-9}. When strings contain hexadecimal notation (e.g. {"0x100"}), base 16 is used as the default instead, but this is overridden if `base` is set to anything other than 16. This function differs from {tonumber()} in the following ways: * If `finite_real` is set, then the function will only return finite real numbers; inputs which would normally produce ±infinity or NaN will instead produce {nil}. * If `no_prefix` is set, then strings which start with {"0x"} will not be interpreted as containing hexadecimal notation, resulting in {nil}. * If `base` is explicitly set to {10}, then strings in hexadecimal notation will always return {nil}. This fixes a bug in {tonumber()}, which treats {base=10} the same as {base} being unset, causing base 16 to be used if `x` contains hexadecimal notation (e.g. {tonumber("0x10", 10)} returns {16}, whereas {tonumber_extended("0x10", 10)} returns {nil}).]==] function export.tonumber_extended(x, base, finite_real, no_prefix) -- TODO: tonumber() maxes out at 2^64 if the base is anything other than 10. -- TODO: support binary (0b) and octal (0o) prefixes. local n = tonumber(x, base) return not ( n == nil or finite_real and n - n ~= 0 or ( -- ±infinity and NaN fail here n ~= x and -- no point using match() on number inputs (base == 10 or no_prefix and (base == nil or base == 16)) and match(x, "^%s*[+-]?0[xX]()") ) ) and n or nil end --[==[ Returns {true} if `x` is a finite real number, or {false} if not. If `x` is a string, it will not be coerced to a number before this check is performed.]==] function export.is_finite_real_number(x) return x and type(x) == "number" and x - x == 0 -- ±infinity and NaN don't give 0 end --[==[ Returns {true} if `x` is an integer, or {false} if not. If `x` is a string, it will not be coerced to a number before this check is performed.]==] function export.is_integer(x) return x and type(x) == "number" and x % 1 == 0 -- ±infinity and NaN also fail here end is_integer = export.is_integer --[==[ Returns {true} if `x` is a positive integer (or zero if the `include_0` flag is set), or {false} if not. If `x` is a string, it will not be coerced to a number before this check is performed.]==] function export.is_positive_integer(x, include_0) return is_integer(x) and (x > 0 or include_0 and x == 0) or false end --[==[ Returns the base-10 logarithm of `x`. This function 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) -- Structured like this so that module documentation works. local log10 = math.log10 if log10 ~= nil then return log10 end local log = math.log return log(10, 10) == 1 and function(x) -- Lua 5.2 return log(x, 10) end or function(x) -- Lua 5.1 return log(x) * 0.43429448190325182765112891891660508229439700580367 -- log10(e) end end export.log10 = export.log10() -- Sets the actual returned function. 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. If `include_prefix` is set, the returned number will include the 0x prefix.]==] function export.to_hex(dec, include_prefix) 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 >= 0x1p64 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%s%X", neg and "-" or "", include_prefix and "0x" or "", dec) end --[==[ Returns the greatest common divisor of an arbitrary number of input numbers.]==] function export.gcd(x, ...) x = tonumber(x) or x if not is_integer(x) then integer_error(x, 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 x ~= 1 then -- If x is 1, validate remaining inputs. -- GCD of two integers x, q with Euclid's algorithm. while q ~= 0 do x, q = q, x % 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[i] end end return x < 0 and -x or x end --[==[ Returns the least common multiple of an arbitrary number of input numbers.]==] function export.lcm(x, ...) x = tonumber(x) or x if not is_integer(x) then integer_error(x, 1, "lcm") end local q, args_len, integers = ..., select("#", ...) -- Compute the product of all inputs as p and GCD as x. for i = 2, args_len + 1 do q = tonumber(q) or q if not is_integer(q) then integer_error(q, i, "lcm") elseif x ~= 0 then -- If x is 0, validate remaining inputs. -- Compute the product. local p = x * q -- GCD of two integers x, q with Euclid's algorithm. while q ~= 0 do x, q = q, x % q end -- Divide product by the GCD to get new LCM. x = p / x 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[i] end end return x < 0 and -x or x end return export