Moduli:math

Nga Enciklopedi Puro Shqiptare
Versioni i datës 10 gusht 2025 08:47 nga Kujdestari7 (diskuto | kontribute) (Krijoi faqen me "local export = {} local byte = string.byte local ceil = math.ceil local floor = math.floor local format = string.format local is_integer -- defined below local match = string.match local select = select local tonumber = tonumber local tonumber_ext -- defined below local tostring = tostring local type = type local INF = math.huge local function sign(x, signed_0) if x > 0 then return 1 elseif x < 0 then return -1 elseif x == 0 then -- 1/(+0) is infinity and 1/(-0...")
(ndrysh) ← Version më i vjetër | shikoni versionin e tanishëm (ndrysh) | Version më i ri → (ndrysh)
Jump to navigation Jump to search

Udhëzuesi për këtë modul mund të krijohet te Moduli:math/doc.

local export = {}

local byte = string.byte
local ceil = math.ceil
local floor = math.floor
local format = string.format
local is_integer -- defined below
local match = string.match
local select = select
local tonumber = tonumber
local tonumber_ext -- defined below
local tostring = tostring
local type = type

local INF = math.huge

local function sign(x, signed_0)
	if x > 0 then
		return 1
	elseif x < 0 then
		return -1
	elseif x == 0 then
		-- 1/(+0) is infinity and 1/(-0) is -infinity.
		return signed_0 and (1 / x > 0 and 1 or -1) or 0
	end
	-- NaN: convert to string with a forced sign prefix, and grab the first byte.
	local sign = byte(format("%+f", x))
	return sign == 0x2B and 1 or -- +
		sign == 0x2D and -1 or -- -
		-- If there's no sign, throw an error. This shouldn't be possible, but
		-- avoids silent errors if it does happen.
		error("Internal error: cannot determine sign of " .. x)
end

--[==[
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)
	if not n or finite_real and (n ~= n or n == INF or n == -INF) then
		return nil
	-- If `base` is explicitly set to 10 (not simply nil), or `no_prefix` is set
	-- and `base` is nil or 16, filter out inputs that started with hexadecimal
	-- prefixes. Note that if `base` is anything else, the initial "0x" will
	-- have been interpreted as digits by tonumber() instead of a prefix (as "x"
	-- can be a digit from base 34 upwards), so there's no prefix to check for.
	elseif base == 10 or no_prefix and (base == nil or base == 16) then
		return not match(x, "^%s*[+-]?0[xX]()") and n or nil
	end
	return n
end
tonumber_ext = export.tonumber_extended

--[==[
Converts `x` to an integer by removing the fractional portion (e.g. {3.5} becomes {3}, and {-2.9} becomes {-2}). This is equivalent to rounding down positive numbers and rounding up negative numbers. If conversion is not possible, returns {nil}.]==]
function export.to_integer(x)
	x = tonumber(x)
	if not (x and x == x and x ~= INF and x ~= -INF) then
		return nil
	elseif x % 1 == 0 then
		return x
	-- Round-down positives.
	elseif x >= 0 then
		return floor(x)
	end
	--Round-up negatives.
	return ceil(x)
end

--[==[
Returns {1} if `x` is positive, {-1} if `x` is negative, or {0} if `x` is {0}.

If `signed_0` is set, this function will only return either {1} or {-1}, and will make a distinction between [[w:signed zero|signed zeroes]] ({+0} and {-0}). This is useful when a {0} result could be disruptive (e.g. {x % 0}).]==]
function export.sign(x, signed_0)
	return sign(
		tonumber(x) or
		error(format("bad argument #1 to 'sign' (number expected, got %s)", type(x)), 2),
		signed_0
	)
end

--[==[
Returns {true} if `x` is a finite real number, or {false} if not.]==]
function export.is_finite_real_number(x)
	return x and x == x and not (x == INF or x == -INF) and type(x) == "number"
end

--[==[
Returns {true} if `x` is an integer, or {false} if not.]==]
function export.is_integer(x)
	return x and type(x) == "number" and x % 1 == 0 or false
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.]==]
function export.is_positive_integer(x, include_0)
	return x and type(x) == "number" and (x > 0 or include_0 and x == 0) and x % 1 == 0 or false
end

--[==[
Returns {true} is `x` is [[w:NaN|NaN]] (Not a Number), or {false} if not.

NaN is a value that has the type "number", but does not represent an actual numeric value; it has the unique property that if {x} is NaN, {x ~= x} evaluates to {true}.]==]
function export.is_NaN(x)
	return x ~= x
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) 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