مواد ڏانھن هلو

ماڊيول:Math

کليل ڄاڻ چيڪلي، وڪيپيڊيا مان

هي ماڊيول ڪيترائي رياضيائي فنڪشن مهيا ڪري ٿو۔ اهي فنڪشن {{#invoke}} ذريعي يا ٻين Lua ماڊيولن مان استعمال ڪري سگهجن ٿا۔

ٻين Lua ماڊيولن مان استعمال

[سنواريو]

عام وڪي صفحن مان هن ماڊيول کي استعمال ڪرڻ لاءِ ڪا خاص تياري ضروري ناهي۔ جيڪڏهن توهان هن ماڊيول کي ڪنهن ٻئي Lua ماڊيول مان استعمال ڪري رهيا آهيو ته پهرين ان کي هن طرح لوڊ ڪرڻو پوندو:

local mm = require('Module:Math')

(هتي mm جو مطلب Module Math آهي؛ جيڪڏهن چاهيو ته توهان وڌيڪ وضاحتي نالو به استعمال ڪري سگهو ٿا۔)

ماڊيول جا گهڻا فنڪشن ٻه نسخا رکن ٿا: هڪ Lua لاءِ ۽ ٻيو {{#invoke}} لاءِ۔ Lua ماڊيولن مان {{#invoke}} فنڪشن به استعمال ڪري سگهجن ٿا، پر Lua فنڪشن استعمال ڪرڻ جو فائدو اهو آهي ته توهان کي Lua جي frame object تائين رسائي جي ضرورت نه پوندي۔ Lua فنڪشنن جي نالن جي شروعات _ سان ٿيندي آهي، جڏهن ته {{#invoke}} فنڪشنن ۾ اهو نه هوندو آهي۔

بي ترتيب

[سنواريو]
{{#invoke:math|random}}  
{{#invoke:math|random|max_value}}  
{{#invoke:math|random|min_value|max_value}}
mm._random()
mm._random(max_value)
mm._random(min_value, max_value)

هڪ بي ترتيب (random) عدد پيدا ڪري ٿو۔

  • جيڪڏهن ڪو دليل (argument) نه هجي ته پيدا ٿيندڙ عدد 0 کان وڏو يا برابر ۽ 1 کان ننڍو هوندو۔
  • جيڪڏهن هڪ دليل ڏنو وڃي ته پيدا ٿيندڙ عدد 1 کان ان دليل تائين صحيح عدد هوندو۔ دليل مثبت صحيح عدد هجڻ گهرجي۔
  • جيڪڏهن ٻه دليل ڏنا وڃن ته پيدا ٿيندڙ عدد انهن ٻن عددن جي وچ ۾ صحيح عدد هوندو۔ ٻنهي دليلن کي صحيح عدد هجڻ گهرجي، پر اهي منفي به ٿي سگهن ٿا۔

هي فنڪشن -232 کان گهٽ يا 232-1 کان وڏن عددن لاءِ صحيح نموني ڪم نٿو ڪري۔ اهڙن حالتن ۾ Module:Random استعمال ڪرڻ صلاح ڏني وڃي ٿي۔

ترتيب

[سنواريو]
{{#invoke:math|order|n}}
mm._order(n)

ڪنهن عدد جي order of magnitude کي طئي ڪري ٿو۔

درستگي

[سنواريو]
{{#invoke:math|precision|n}}  
{{#invoke:math|precision|x=n}}
mm._precision(number_string)

ڪنهن عدد جي precision طئي ڪري ٿو۔ مثال طور:

  • "4" لاءِ نتيجو "0"
  • "4.567" لاءِ نتيجو "3"
  • "100" لاءِ نتيجو "-2"

هي فنڪشن عدد جي string صورت کي پڙهي ٿو ۽ اهو به ڏسي ٿو ته ڇا عدد E notation ۾ آهي يا نه۔ تمام وڏن يا تمام وڌيڪ درست عددن کي Lua ۾ string طور داخل ڪرڻ بهتر آهي۔

وڏو عدد

[سنواريو]
{{#invoke:math|max|v1|v2|v3|...}}
mm._max(v1, v2, v3, ...)

ڏنل عددن مان سڀ کان وڏو عدد واپس ڪري ٿو۔ جيڪي قدر عدد ۾ تبديل نه ٿي سگهن، انهن کي نظرانداز ڪيو ويندو آهي۔

وچولو عدد

[سنواريو]
{{#invoke:math|median|v1|v2|v3|...}}
mm._median(v1, v2, v3, ...)

ڏنل قدرن مان median واپس ڪري ٿو۔

ننڍو عدد

[سنواريو]
{{#invoke:math|min|v1|v2|v3|...}}
mm._min(v1, v2, v3, ...)

ڏنل قدرن مان سڀ کان ننڍو عدد واپس ڪري ٿو۔

حساب

[سنواريو]
{{#invoke:math|sum|v1|v2|v3|...}}
mm._sum(v1, v2, v3, ...)

ڏنل عددن جو مجموعو (sum) واپس ڪري ٿو۔

سراسري

[سنواريو]
{{#invoke:math|average|v1|v2|v3|...}}
mm._average(v1, v2, v3, ...)

ڏنل عددن جو اوسط (average) واپس ڪري ٿو۔ (وڌيڪ صحيح لفظن ۾، هي arithmetic mean آهي۔)

سڌو انگ

[سنواريو]
{{#invoke:math|round|value|precision}}  
{{#invoke:math|round|value=value|precision=precision}}
mm._round(value, precision)

ڪنهن عدد کي مخصوص precision تائين round ڪري ٿو۔ ڊفالٽ طور precision = 0 هوندي آهي، يعني ويجهي صحيح عدد تائين۔

فارمولو:

10 لاگ

[سنواريو]
{{#invoke:math | log10 | x}}
mm._log10(x)

عدد x جو بنياد 10 وارو logarithm واپس ڪري ٿو۔

{{#invoke:math|mod|x|y}}
mm._mod(x, y)

عدد x کي y سان ورهائڻ بعد بچيل باقي (remainder) واپس ڪري ٿو۔

جي سي ڊي

[سنواريو]
{{#invoke:math|gcd|v1|v2|...}}
mm._gcd(v1, v2, ...)

ڏنل عددن جو greatest common divisor (GCD) ڳولي ٿو۔

درست_نمونو

[سنواريو]
{{#invoke:math|precision_format|value_string|precision}}
mm._precision_format(value_string, precision)

عدد کي مخصوص precision تائين round ڪري string طور فارميٽ ڪري ٿو۔

{{#invoke:Math|divide|x|y|round=|precision=}}
mm._divide(x, y, round, precision)

x کي y سان ورهائي ٿو۔

  • جيڪڏهن y عدد نه هجي ته y واپس ڪيو ويندو۔
  • جيڪڏهن x عدد نه هجي ته x واپس ڪيو ويندو۔
  • جيڪڏهن round صحيح هجي ته نتيجي ۾ decimal نه هوندي۔
  • precision نتيجي جي درستگي طئي ڪري ٿي۔

صاف انگ

[سنواريو]
local number, number_string = mm._cleanNumber(number_string)

هي مددگار فنڪشن آهي جيڪو ٻين Lua ماڊيولن مان سڏي سگهجي ٿو، پر {{#invoke}} مان نه۔

هي string يا عدد کي وٺي ان کي عدد ۾ تبديل ڪرڻ جي ڪوشش ڪندو آهي۔ جيڪڏهن ڪامياب ٿيو ته عدد ۽ ان جي string صورت واپس ڪندو، ٻي صورت ۾ nil, nil موٽائيندو۔

پڻ ڏسو

[سنواريو]



--[[

This module provides a number of basic mathematical operations.

]]

local yesno, getArgs -- lazily initialized

local p = {} -- Holds functions to be returned from #invoke, and functions to make available to other Lua modules.
local wrap = {} -- Holds wrapper functions that process arguments from #invoke. These act as intemediary between functions meant for #invoke and functions meant for Lua.

--[[
Helper functions used to avoid redundant code.
]]

local function err(msg)
	-- Generates wikitext error messages.
	return mw.ustring.format('<strong class="error">Formatting error: %s</strong>', msg)
end

local function unpackNumberArgs(args)
	-- Returns an unpacked list of arguments specified with numerical keys.
	local ret = {}
	for k, v in pairs(args) do
		if type(k) == 'number' then
			table.insert(ret, v)
		end
	end
	return unpack(ret)
end

local function makeArgArray(...)
	-- Makes an array of arguments from a list of arguments that might include nils.
	local args = {...} -- Table of arguments. It might contain nils or non-number values, so we can't use ipairs.
	local nums = {} -- Stores the numbers of valid numerical arguments.
	local ret = {}
	for k, v in pairs(args) do
		v = p._cleanNumber(v)
		if v then
			nums[#nums + 1] = k
			args[k] = v
		end
	end
	table.sort(nums)
	for i, num in ipairs(nums) do
		ret[#ret + 1] = args[num]
	end
	return ret
end

local function fold(func, ...)
	-- Use a function on all supplied arguments, and return the result. The function must accept two numbers as parameters,
	-- and must return a number as an output. This number is then supplied as input to the next function call.
	local vals = makeArgArray(...)
	local count = #vals -- The number of valid arguments
	if count == 0 then return
		-- Exit if we have no valid args, otherwise removing the first arg would cause an error.
		nil, 0
	end
	local ret = table.remove(vals, 1)
	for _, val in ipairs(vals) do
		ret = func(ret, val)
	end
	return ret, count
end

--[[
Fold arguments by selectively choosing values (func should return when to choose the current "dominant" value).
]]
local function binary_fold(func, ...)
	local value = fold((function(a, b) if func(a, b) then return a else return b end end), ...)
	return value
end

--[[
random

Generate a random number

Usage:
{{#invoke: Math | random }}
{{#invoke: Math | random | maximum value }}
{{#invoke: Math | random | minimum value | maximum value }}
]]

function wrap.random(args)
	local first = p._cleanNumber(args[1])
	local second = p._cleanNumber(args[2])
	return p._random(first, second)
end

function p._random(first, second)
	math.randomseed(mw.site.stats.edits + mw.site.stats.pages + os.time() + math.floor(os.clock() * 1000000000))
	-- math.random will throw an error if given an explicit nil parameter, so we need to use if statements to check the params.
	if first and second then
		if first <= second then -- math.random doesn't allow the first number to be greater than the second.
			return math.random(first, second)
		end
	elseif first then
		return math.random(first)
	else
		return math.random()
	end
end

--[[
order

Determine order of magnitude of a number

Usage:
{{#invoke: Math | order | value }}
]]

function wrap.order(args)
	local input_string = (args[1] or args.x or '0');
	local input_number = p._cleanNumber(input_string);
	if input_number == nil then
		return err('order of magnitude input appears non-numeric')
	else
		return p._order(input_number)
	end
end

function p._order(x)
	if x == 0 then return 0 end
	return math.floor(math.log10(math.abs(x)))
end

--[[
precision

Detemines the precision of a number using the string representation

Usage:
{{ #invoke: Math | precision | value }}
]]

function wrap.precision(args)
	local input_string = (args[1] or args.x or '0');
	local trap_fraction = args.check_fraction;
	local input_number;

	if not yesno then
		yesno = require('Module:Yesno')
	end
	if yesno(trap_fraction, true) then -- Returns true for all input except nil, false, "no", "n", "0" and a few others. See [[Module:Yesno]].
		local pos = string.find(input_string, '/', 1, true);
		if pos ~= nil then
			if string.find(input_string, '/', pos + 1, true) == nil then
				local denominator = string.sub(input_string, pos+1, -1);
				local denom_value = tonumber(denominator);
				if denom_value ~= nil then
					return math.log10(denom_value);
				end
			end
		end
	end

	input_number, input_string = p._cleanNumber(input_string);
	if input_string == nil then
		return err('precision input appears non-numeric')
	else
		return p._precision(input_string)
	end
end

function p._precision(x)
	if type(x) == 'number' then
		x = tostring(x)
	end
	x = string.upper(x)

	local decimal = x:find('%.')
	local exponent_pos = x:find('E')
	local result = 0;

	if exponent_pos ~= nil then
		local exponent = string.sub(x, exponent_pos + 1)
		x = string.sub(x, 1, exponent_pos - 1)
		result = result - tonumber(exponent)
	end

	if decimal ~= nil then
		result = result + string.len(x) - decimal
		return result
	end

	local pos = string.len(x);
	while x:byte(pos) == string.byte('0') do
		pos = pos - 1
		result = result - 1
		if pos <= 0 then
			return 0
		end
	end

	return result
end


--[[
max

Finds the maximum argument

Usage:
{{#invoke:Math| max | value1 | value2 | ... }}

Note, any values that do not evaluate to numbers are ignored.
]]

function wrap.max(args)
	return p._max(unpackNumberArgs(args))
end

function p._max(...)
	local max_value = binary_fold((function(a, b) return a > b end), ...)
	if max_value then
		return max_value
	end
end

--[[
median

Find the median of set of numbers

Usage:
{{#invoke:Math | median | number1 | number2 | ...}}
OR
{{#invoke:Math | median }}
]]

function wrap.median(args)
	return p._median(unpackNumberArgs(args))
end

function p._median(...)
	local vals = makeArgArray(...)
	local count = #vals
	table.sort(vals)

	if count == 0 then
		return 0
	end

	if p._mod(count, 2) == 0 then
		return (vals[count/2] + vals[count/2+1])/2
	else
		return vals[math.ceil(count/2)]
	end
end

--[[
min

Finds the minimum argument

Usage:
{{#invoke:Math| min | value1 | value2 | ... }}
OR
{{#invoke:Math| min }}

When used with no arguments, it takes its input from the parent
frame.  Note, any values that do not evaluate to numbers are ignored.
]]

function wrap.min(args)
	return p._min(unpackNumberArgs(args))
end

function p._min(...)
	local min_value = binary_fold((function(a, b) return a < b end), ...)
	if min_value then
		return min_value
	end
end

--[[
sum

Finds the sum

Usage:
{{#invoke:Math| sum | value1 | value2 | ... }}
OR
{{#invoke:Math| sum }}

Note, any values that do not evaluate to numbers are ignored.
]]

function wrap.sum(args)
	return p._sum(unpackNumberArgs(args))
end

function p._sum(...)
	local sums, count = fold((function(a, b) return a + b end), ...)
	if not sums then
		return 0
	else
		return sums
	end
end

--[[
average

Finds the average

Usage:
{{#invoke:Math| average | value1 | value2 | ... }}
OR
{{#invoke:Math| average }}

Note, any values that do not evaluate to numbers are ignored.
]]

function wrap.average(args)
	return p._average(unpackNumberArgs(args))
end

function p._average(...)
	local sum, count = fold((function(a, b) return a + b end), ...)
	if not sum then
		return 0
	else
		return sum / count
	end
end

--[[
round

Rounds a number to specified precision

Usage:
{{#invoke:Math | round | value | precision }}

--]]

function wrap.round(args)
	local value = p._cleanNumber(args[1] or args.value or 0)
	local precision = p._cleanNumber(args[2] or args.precision or 0)
	if value == nil or precision == nil then
		return err('round input appears non-numeric')
	else
		return p._round(value, precision)
	end
end

function p._round(value, precision)
	local rescale = math.pow(10, precision or 0);
	return math.floor(value * rescale + 0.5) / rescale;
end

--[[
log10

returns the log (base 10) of a number

Usage:
{{#invoke:Math | log10 | x }}
]]

function wrap.log10(args)
	return math.log10(args[1])
end

--[[
mod

Implements the modulo operator

Usage:
{{#invoke:Math | mod | x | y }}

--]]

function wrap.mod(args)
	local x = p._cleanNumber(args[1])
	local y = p._cleanNumber(args[2])
	if not x then
		return err('first argument to mod appears non-numeric')
	elseif not y then
		return err('second argument to mod appears non-numeric')
	else
		return p._mod(x, y)
	end
end

function p._mod(x, y)
	local ret = x % y
	if not (0 <= ret and ret < y) then
		ret = 0
	end
	return ret
end

--[[
gcd

Calculates the greatest common divisor of multiple numbers

Usage:
{{#invoke:Math | gcd | value 1 | value 2 | value 3 | ... }}
--]]

function wrap.gcd(args)
	return p._gcd(unpackNumberArgs(args))
end

function p._gcd(...)
	local function findGcd(a, b)
		local r = b
		local oldr = a
		while r ~= 0 do
			local quotient = math.floor(oldr / r)
			oldr, r = r, oldr - quotient * r
		end
		if oldr < 0 then
			oldr = oldr * -1
		end
		return oldr
	end
	local result, count = fold(findGcd, ...)
	return result
end

--[[
precision_format

Rounds a number to the specified precision and formats according to rules
originally used for {{template:Rnd}}.  Output is a string.

Usage:
{{#invoke: Math | precision_format | number | precision }}
]]

function wrap.precision_format(args)
	local value_string = args[1] or 0
	local precision = args[2] or 0
	return p._precision_format(value_string, precision)
end

function p._precision_format(value_string, precision)
	-- For access to Mediawiki built-in formatter.
	local lang = mw.getContentLanguage();

	local value
	value, value_string = p._cleanNumber(value_string)
	precision = p._cleanNumber(precision)

	-- Check for non-numeric input
	if value == nil or precision == nil then
		return err('invalid input when rounding')
	end

	local current_precision = p._precision(value)
	local order = p._order(value)

	-- Due to round-off effects it is neccesary to limit the returned precision under
	-- some circumstances because the terminal digits will be inaccurately reported.
	if order + precision >= 14 then
		if order + p._precision(value_string) >= 14 then
			precision = 13 - order;
		end
	end

	-- If rounding off, truncate extra digits
	if precision < current_precision then
		value = p._round(value, precision)
		current_precision = p._precision(value)
	end

	local formatted_num = lang:formatNum(math.abs(value))
	local sign

	-- Use proper unary minus sign rather than ASCII default
	if value < 0 then
		sign = '−'
	else
		sign = ''
	end

	-- Handle cases requiring scientific notation
	if string.find(formatted_num, 'E', 1, true) ~= nil or math.abs(order) >= 9 then
		value = value * math.pow(10, -order)
		current_precision = current_precision + order
		precision = precision + order
		formatted_num = lang:formatNum(math.abs(value))
	else
		order = 0;
	end
	formatted_num = sign .. formatted_num

	-- Pad with zeros, if needed
	if current_precision < precision then
		local padding
		if current_precision <= 0 then
			if precision > 0 then
				local zero_sep = lang:formatNum(1.1)
				formatted_num = formatted_num .. zero_sep:sub(2,2)

				padding = precision
				if padding > 20 then
					padding = 20
				end

				formatted_num = formatted_num .. string.rep('0', padding)
			end
		else
			padding = precision - current_precision
			if padding > 20 then
				padding = 20
			end
			formatted_num = formatted_num .. string.rep('0', padding)
		end
	end

	-- Add exponential notation, if necessary.
	if order ~= 0 then
		-- Use proper unary minus sign rather than ASCII default
		if order < 0 then
			order = '−' .. lang:formatNum(math.abs(order))
		else
			order = lang:formatNum(order)
		end

		formatted_num = formatted_num .. '<span style="margin:0 .15em 0 .25em">×</span>10<sup>' .. order .. '</sup>'
	end

	return formatted_num
end

--[[
divide

Implements the division operator

Usage:
{{#invoke:Math | divide | x | y | round= | precision= }}

--]]
function wrap.divide(args)
	local x = args[1]
	local y = args[2]
	local round = args.round
	local precision =  args.precision
	if not yesno then
		yesno = require('Module:Yesno')
	end
	return p._divide(x, y, yesno(round), precision)
end

function p._divide(x, y, round, precision)
	if y == nil or y == "" then
		return err("Empty divisor")
	elseif not tonumber(y) then
		if type(y) == 'string' and string.sub(y, 1, 1) == '<' then
			return y
		else
			return err("Not a number: " .. y)
		end
	elseif x == nil or x == "" then
		return err("Empty dividend")
	elseif not tonumber(x) then
		if type(x) == 'string' and string.sub(x, 1, 1) == '<' then
			return x
		else
			return err("Not a number: " .. x)
		end
	else
		local z = x / y
		if round then
			return p._round(z, 0)
		elseif precision then
			return p._round(z, precision)
		else
			return z	
		end
	end
end

--[[
Helper function that interprets the input numerically.  If the
input does not appear to be a number, attempts evaluating it as
a parser functions expression.
]]

function p._cleanNumber(number_string, unformat)
	if type(number_string) == 'number' then
		-- We were passed a number, so we don't need to do any processing.
		return number_string, tostring(number_string)
	elseif type(number_string) ~= 'string' or not number_string:find('%S') then
		-- We were passed a non-string or a blank string, so exit.
		return nil, nil;
	end

	-- Attempt basic conversion
	local number = tonumber(number_string)
	
	-- If failed, try unformatting the number_string
	if unformat and number == nil then
		-- Cannot use mw.language.getContentLanguage():parseFormattedNumber()
		-- because, unlike {{formatnum:|R}}, it won't ignore operators (it
		-- would return an error on "1,234+1,234" instead of "1234+1234")
		number_string = mw.getCurrentFrame():callParserFunction("formatnum", {number_string, "R"})
		number = tonumber(number_string)
	end

	-- If failed, attempt to evaluate input as an expression
	if number == nil then
		local success, result = pcall(mw.ext.ParserFunctions.expr, number_string)
		if success then
			number = tonumber(result)
			number_string = tostring(number)
		else
			number = nil
			number_string = nil
		end
	else
		number_string = number_string:match("^%s*(.-)%s*$") -- String is valid but may contain padding, clean it.
		number_string = number_string:match("^%+(.*)$") or number_string -- Trim any leading + signs.
		if number_string:find('^%-?0[xX]') then
			-- Number is using 0xnnn notation to indicate base 16; use the number that Lua detected instead.
			number_string = tostring(number)
		end
	end

	return number, number_string
end

--[[
Wrapper function that does basic argument processing. This ensures that all functions from #invoke can use either the current
frame or the parent frame, and it also trims whitespace for all arguments and removes blank arguments.
]]

local mt = { __index = function(t, k)
	return function(frame)
		if not getArgs then
			getArgs = require('Module:Arguments').getArgs
		end
		return wrap[k](getArgs(frame))  -- Argument processing is left to Module:Arguments. Whitespace is trimmed and blank arguments are removed.
	end
end }

return setmetatable(p, mt)