en.wiktionary.org

Module:math - Wiktionary, the free dictionary


The following documentation is located at Module:math/documentation. [edit]
Useful links: subpage listlinkstransclusionstestcasessandbox

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 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).

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