Модуль:Math/тести

{{i}} Документація модуля[перегляд] [редагувати] [історія] [очистити кеш]


Цей модуль забезпечує ряд математичних функцій. Ці функції можуть використовуватися з #invoke чи іншими модулями Lua.

Використання з іншим модулем Lua

Щоб використовувати цей модуль на звичайних вікісторінках, спеціальні знання не потрібні. Якщо ви використовуєте цей модуль з іншим модулем Lua, то вам спочатку потрібно його завантажити як на прикладі:

local mm = require('Module:Math')

(Змінна mm розшифровується як Module Math; за бажанням ви можете вибрати щось більш описове.)

Більшість функцій модуля є у версії для Lua й у версії для #invoke. Можна використовувати функції #invoke з іншими модулями Lua, але використання функції Lua має перевагу в тому, що вам не потрібно отримувати доступ до Lua frame object. Функціям Lua передує _, тоді як #invoke функцій немає.

random

Див. також: en:Module:Random
{{#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)

Генерує випадкове число.

  • Якщо аргументи не вказані, то згенероване число більше або дорівнює 0 і менше ніж 1.
  • Якщо один з аргументів наданий, генерується ціле число від 1 до заданого аргументу. Аргумент повинен бути цілим додатнім числом.
  • Якщо надані обидва аргументи, генерується ціле число між першим і другим аргументом. Обидва аргументи повинні бути цілими, але можуть бути й від'ємними.

Функція не працюватиме належним чином для чисел менше -2^32 і більше, ніж 2^32 - 1 (може змінюватися залежно від обладнання). Якщо вам потрібно використовувати цифри поза цим діапазоном, рекомендується використовувати en:Module:Random.

order

{{#invoke:math|order|n}}
mm._order(n)

Визначає порядок величини числа.

precision

{{#invoke:math|precision|n}}
{{#invoke:math|precision|x=n}}
mm._precision(number_string)

Визначає точність числа. Наприклад, для "4" поверне "0", для "4.567" поверне "3", і для "100" поверне "-2".

Функція намагається проаналізувати строкове подання числа, і виявляє, чи використовує число у експоненціальному записі. З цієї причини коли викликається з Lua, дуже великі або дуже точні цифри, вони повинні відразу надходити як рядки задля отримання точного результату. Якщо вони вводяться як числа, інтерпретатор Lua зміниться їх експоненціальним записом і ця функція поверне точний експоненціальний запис, а не розмір початкового числа. Це не проблема, коли число викликається з #invoke, завдяки участі #invoke все подається в рядковому форматі.

max

{{#invoke:math|max|v1|v2|v3|...}}
mm._max(v1, v2, v3, ...)

Повертає максимальне значення із вказаних значень. Значення, які не можуть бути перетворені в числа, ігноруються.

median

{{#invoke:math|median|v1|v2|v3|...}}
mm._median(v1, v2, v3, ...)

Повертає значення медіани з вказаних значень. Значення, які не можуть бути перетворені в числа, ігноруються.

min

{{#invoke:math|min|v1|v2|v3|...}}
mm._min(v1, v2, v3, ...)

Повертає мінімальне значення із вказаних значень. Значення, які не можуть бути перетворені в числа, ігноруються.

sum

{{#invoke:math|sum|v1|v2|v3|...}}
mm._sum(v1, v2, v3, ...)

Повертає суму зазначених значень. Значення, які не можуть бути перетворені в числа, ігноруються.

average

{{#invoke:math|average|v1|v2|v3|...}}
mm._average(v1, v2, v3, ...)

Повертає середнє значення із вказаних. (Точніше, це значення відповідає середньому арифметичному.) Значення, які не можуть бути перетворені в числа, ігноруються.

round

{{#invoke:math|round|value|precision}}
{{#invoke:math|round|value=value|precision=precision}}
mm._round(value, precision)

Округлює число до заданої точності як степені 10 (стандартним значення є 0, що означає до найближчого цілого числа).

Це робиться за наступною формулою:

Зверніть увагу: Станом на жовтень 2019, є баг у відображені деяких округлених чисел. Коли намагатися округлити число, що округлюється до «n.0», як «1.02», до найближчого десятка (тобто |r=1), то ця функція повинна відобразити «1.0», але неочікувано вона відображає «1». Натомість використайте параметр |precision_format=.

log10

{{#invoke:math | log10 | x}}
mm._log10(x)

Повертає log10(x), логарифм x з основою 10.

mod

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

Отримує x по модулю y, або залишок після x поділеного на y. Це працює належним чином для цілих чисел до 2^53; для більших чисел оператор за модулем Lua може повертати хибне значення. Ця функція розв'язує цю проблему повертаючи 0 якщо по модулю оператору модуля Lua дається значення, яке становить менше ніж 0 або більше ніж y.

gcd

{{#invoke:math|gcd|v1|v2|...}}
mm._gcd(v1, v2, ...)

Знаходить найбільший спільний дільник із встановленого значення. Значення, які не можуть бути перетворені в числа, ігноруються.

precision_format

{{#invoke:math|precision_format|value_string|precision}}
mm._precision_format(value_string, precision)

Заокруглення числа із зазначеною точністю і форматом відповідно до правил спочатку використовувалися для {{Rnd}}. Видається рядком.

Параметр precision повинен бути цілим числом цифр після десяткової коми. Дозволяються від'ємні значення. Нецілі числа дають неочікувані результати. Додатні значення більші ніж зазначена точність додають відступи нулями, від'ємні значення більша ніж зазначений порядок можуть поглинути усі цифри.

Оформлення 8765,567 з {{[[Шаблон:#invoke:Math|#invoke:Math]]|precision_format|8765.567|точність}} дає:

точність Результат
2 8765,57
-2 8800
6 8765,567000
-6 0
2.5 8765,5680426633
-2.5 8854,3774484715

divide

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

Ділення x на y.

  • Якщо y не є числом, то повертається його значення.
  • В іншому випадку, якщо x не є числом, то повертається його значення.
  • Якщо round є true («yes» або «так» для #invoke), то результат не міститиме десяткових дробів
  • Точність вказує скільки цифр точності результат повинен мати

Якщо будь-який аргумент містить теги HTML, то вони повертаються незміненими, дозволяючи передавати будь-які помилки, які виникли під час обрахування аргументів функцією ділення, шаблону, який викликається.

cleanNumber

local number, number_string = mm._cleanNumber(number_string)

Допоміжна функція, яка може бути викликана з інших модулів Lua, але не від #invoke. Вона приймає рядкове або числове значення як вхідних даних, і, якщо значення може бути перетворено в число, cleanNumber повертає число і рядок цифр. Якщо значення не може бути перетворено в число, cleanNumber повертає nil, nil.

-- Unit tests for [[Module:Math/sandbox]]. Click talk page to run tests.

local moduleName = 'Math/пісочниця' -- assigning this to a variable as it is later used to generate an #invoke statement.
local mm = require('Module:' .. moduleName)
local ScribuntoUnit = require('Module:ScribuntoUnit')
local suite = ScribuntoUnit:new()

-------------------------------------------------------------------------------
-- Helper functions
-------------------------------------------------------------------------------

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

function suite.getLuaResult(funcName, args)
	args = args or {}
	local result = mm['_' .. funcName](unpack(args))
	return result
end

function suite:assertLuaEquals(expected, funcName, args)
	args = args or {}
	self:assertEquals(expected, self.getLuaResult(funcName, args))
end

function suite.buildInvocation(funcName, args)
	args = args or {}
	local argsClone = mw.clone(args)
	-- Build a module invocation equivalent to the args table. Taken from [[Module:Unsubst]].
	-- Numbered args first.
	local ret = '{{#invoke:' .. moduleName .. '|' .. funcName
	for k, v in ipairs(argsClone) do
		v = tostring(v)
		if string.find(v, '=', 1, true) then
			-- likely something like 1=foo=bar, we need to do it as a named arg
			break
		end
		ret = ret .. '|' .. v
		argsClone[k] = nil
	end
	for k, v in pairs(argsClone) do
		k = tostring(k)
		v = tostring(v)
		ret = ret .. '|' .. k .. '=' .. v
	end
	return ret .. '}}'
end

function suite:getInvokeResult(funcName, args, convertNumber) -- Unless convertNumber is false, the number is converted to a number, if possible, on re-entry to Lua.
	args = args or {}
	local invocation = self.buildInvocation(funcName, args)
	local result = self.frame:preprocess(invocation)
	if convertNumber ~= false and tonumber(result) then
		return tonumber(result)
	else
		return result
	end
end

function suite:assertInvokeEquals(expected, funcName, args, convertNumber)
	args = args or {}
	local invokeResult = self:getInvokeResult(funcName, args, convertNumber)
	self:assertEquals(expected, invokeResult)
end

function suite:assertLuaAndInvokeTrue(trueFunc, funcName, args, convertNumber)
	args = args or {}
	local invokeResult = self:getInvokeResult(funcName, args, convertNumber)
	local luaResult = self.getLuaResult(funcName, args)
	self:assertTrue(trueFunc(invokeResult))
	self:assertTrue(trueFunc(luaResult))
end

function suite:assertLuaAndInvokeEqual(funcName, testTable, convertNumber)
	local expected = testTable[1]
	local args = testTable[2] or {}
	self:assertLuaEquals(expected, funcName, args)
	self:assertInvokeEquals(expected, funcName, args, convertNumber)
end

function suite:assertLuaAndInvokeEqualMany(funcName, testTables, convertNumber)
	for i, testTable in ipairs(testTables) do
		self:assertLuaAndInvokeEqual(funcName, testTable, convertNumber)
	end
end

-------------------------------------------------------------------------------
-- Test random
-------------------------------------------------------------------------------

function suite:test_random()
	self:assertLuaAndInvokeTrue(function (n) return n >= 0 and n < 1 end, 'random')
	self:assertLuaAndInvokeTrue(function (n) return n == 1 or n == 2 end, 'random', {2})
	self:assertLuaAndInvokeTrue(function (n) return n >= 1 and n <= 10 and math.floor(n) == n end, 'random', {10})
	self:assertLuaAndInvokeTrue(function (n) return n >= 10 and n <= 20 and math.floor(n) == n end, 'random', {10, 20})
end

-------------------------------------------------------------------------------
-- Test max
-------------------------------------------------------------------------------
 
function suite:test_max()
	local tests = {
		{9, {5, 6, 9}},
		{-5, {-5, -6, -9}},
	}
	self:assertLuaAndInvokeEqualMany('max', tests)
	self:assertLuaEquals(nil, 'max', {})
	self:assertInvokeEquals('', 'max', {})
end

-------------------------------------------------------------------------------
-- Test average
-------------------------------------------------------------------------------

function suite:test_average()
	local tests = {
		{6, {5, 6, 7}},
		{-7, {-7}},
		{10000000002, {10000000001, 10000000002, 10000000003}},
	}
	self:assertLuaAndInvokeEqualMany('average', tests)
end
 
-------------------------------------------------------------------------------
-- Test min
-------------------------------------------------------------------------------

function suite:test_min()
	local tests = {
		{1, {1, 2, 3}},
		{-3, {-1, -2, -3}},
	}
	self:assertLuaAndInvokeEqualMany('min', tests)
	self:assertLuaEquals(nil, 'min', {})
	self:assertInvokeEquals('', 'min', {})
end

-------------------------------------------------------------------------------
-- Test gcd
-------------------------------------------------------------------------------

function suite:test_gcd()
	local tests = {
		{4, {12, 8}},
		{2, {12, 8, 6}},
		{4, {-12, -8}},
		{2, {-12, -8, -6}},
		{8, {0, 8}},
		{8, {0, -8}},
		{0, {0}},
		{0, {0, 0}},
		{4, {12, nil, 8}},
	}
	self:assertLuaAndInvokeEqualMany('gcd', tests)
end

-------------------------------------------------------------------------------
-- Test order
-------------------------------------------------------------------------------

function suite:test_order()
	local tests = {
		{0, {2}},
		{1, {20}},
		{2, {200}},
		{0, {5}},
	}
	self:assertLuaAndInvokeEqualMany('order', tests)
	self:assertInvokeEquals(suite.err('order of magnitude input appears non-numeric'), 'order', {'string'})
	self:assertInvokeEquals(0, 'order', {x = 5})
end

-------------------------------------------------------------------------------
-- Test precision
-------------------------------------------------------------------------------

function suite:test_precison()
	local tests = {
		{4, {1.9856}},
		{1, {1.1}},
		{10, {1.9999999999}},
		{9, {0.000020004}},
	}
	self:assertLuaAndInvokeEqualMany('precision', tests)
	self:assertInvokeEquals(suite.err('precision input appears non-numeric'), 'precision', {'letra'})
	self:assertInvokeEquals(4, 'precision', {x = '1.9888'})
end

-------------------------------------------------------------------------------
-- Test round
-------------------------------------------------------------------------------

function suite:test_round()
	local tests = {
		{2, {1.99999}},
		{2, {1.99999, 0}},
		{1.9, {1.94, 1}},
		{20, {15, -1}},
		{2.0004e-05, {0.000020004}}, -- broken and returns 0 due to limit of order -5 of phps floating number 
		{2.0004e-05, {0.000020004, mm._precision(0.000020004)}}, -- works
	}
	self:assertLuaAndInvokeEqualMany('round', tests)
	self:assertInvokeEquals(3, 'round', {value = '2.99999', precision = '2'})
end

-------------------------------------------------------------------------------
-- Test mod
-------------------------------------------------------------------------------

function suite:test_mod()
	local tests = {
		{0, {10, 2}},
		{1, {11, 2}},
		{0, {525000000000000120000000000, 3}}, -- With the plain % operator this returns 68719476736 due to floating point error.
	}
	self:assertLuaAndInvokeEqualMany('mod', tests)
	self:assertInvokeEquals(suite.err('first argument to mod appears non-numeric'), 'mod', {})
	self:assertInvokeEquals(suite.err('second argument to mod appears non-numeric'), 'mod', {1})
	local successNoArgs = pcall(mm._mod)
	self:assertFalse(successNoArgs)
	local successOneArg = pcall(mm._mod, 1)
	self:assertFalse(successOneArg)
end

-------------------------------------------------------------------------------
-- Test precision format
-------------------------------------------------------------------------------

function suite:test_precison_format()
	local tests = {
		{'10.00', {10, 2}},
		{'2.00<span style="margin:0 .15em 0 .25em">×</span>10<sup>−5</sup>', {0.000020004, 7}}
	}
	self:assertLuaAndInvokeEqualMany('precision_format', tests, false) -- the "false" stops string values being converted to numbers on re-entry from #invoke.
end

-------------------------------------------------------------------------------
-- Test cleanNumber
-------------------------------------------------------------------------------

function suite:assertCleanNumberEquals(expectedTable, inputString)
	local expectedNum, expectedNumString = expectedTable[1], expectedTable[2]
	local actualNum, actualNumString = mm._cleanNumber(inputString)
	self:assertEquals(expectedNum, actualNum)
	self:assertEquals(expectedNumString, actualNumString)
end

function suite:test_cleanNumber()
	self:assertCleanNumberEquals({0, '0'}, '0')
	self:assertCleanNumberEquals({1, '1'}, 1)
	self:assertCleanNumberEquals({2, '2'}, '  2  ')
	self:assertCleanNumberEquals({3, '3'}, '4-1')
	self:assertCleanNumberEquals({4, '4'}, '2 + 2')
	self:assertCleanNumberEquals({5, '5'}, '  2 + 3  ')
	self:assertCleanNumberEquals({6, '6'}, '+6')
	self:assertCleanNumberEquals({-7, '-7'}, '-7')
	self:assertCleanNumberEquals({88, '88'}, '0x58')
	self:assertCleanNumberEquals({1000000000, '1e+9'}, '1e+9')
	self:assertCleanNumberEquals({-88, '-88'}, '-0x58')
	self:assertCleanNumberEquals({0.16667, '0.16667'}, '1/6 round 5')
	self:assertCleanNumberEquals({nil, nil}, '1 foo 2') -- invalid expression
	self:assertCleanNumberEquals({nil, nil}, '1+') -- missing expr operand
	self:assertCleanNumberEquals({nil, nil}, '')
	self:assertCleanNumberEquals({nil, nil}, '  ')
	self:assertCleanNumberEquals({nil, nil}, 'string')
	self:assertCleanNumberEquals({nil, nil}, '  string with padding  ')
end
-------------------------------------------------------------------------------
-- Test divide
-------------------------------------------------------------------------------

function suite:test_divide() 
	self:assertInvokeEquals('1','divide',{1, 2, round = 'yes'}, false)
	self:assertInvokeEquals('0.5','divide',{1, 2, round = 'no'}, false)
	self:assertInvokeEquals('0','divide',{1, 3, round = 'yes', precision=2}, false)
	self:assertInvokeEquals('0.33','divide',{1, 3, precision=2}, false)
	self:assertInvokeEquals(suite.err('Empty dividend'),'divide',{'',2},false)
	self:assertInvokeEquals(suite.err('Empty divisor'),'divide',{1,''},false)
	self:assertInvokeEquals(suite.err('Empty divisor'),'divide',{},false)
	self:assertInvokeEquals(suite.err('Empty divisor'),'divide',{'',''},false)
	self:assertInvokeEquals(suite.err('Not a number: a'),'divide',{'a',2},false)
	self:assertInvokeEquals(suite.err('Not a number: b'),'divide',{1,'b'},false)
	self:assertInvokeEquals(suite.err('Not a number: b'),'divide',{'a','b'},false)
	self:assertInvokeEquals('<big>Bad</big>','divide',{'<big>Bad</big>',2},false)
	self:assertInvokeEquals('<big>Bad</big>','divide',{1,'<big>Bad</big>'},false)
	self:assertInvokeEquals('<big>Bad2</big>','divide',{'<big>Bad1</big>','<big>Bad2</big>'},false)
end
return suite
Prefix: a b c d e f g h i j k l m n o p q r s t u v w x y z 0 1 2 3 4 5 6 7 8 9

Portal di Ensiklopedia Dunia

Kembali kehalaman sebelumnya