Module:Math: Difference between revisions

m
1 revision imported from wikipedia:Module:Math
en>Mr. Stradivarius
(replace frame:preprocess with frame:callParserFunction per protected edit request by User:Jackmcbarn)
m (1 revision imported from wikipedia:Module:Math)
 
(13 intermediate revisions by 6 users not shown)
Line 5:
]]
 
local yesno, =getArgs require('Module:Yesno')-- lazily initialized
local getArgs = require('Module:Arguments').getArgs
 
local p = {} -- Holds functions to be returned from #invoke, and functions to make available to other Lua modules.
Line 50 ⟶ 49:
end
 
local function applyFuncToArgsfold(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
Line 64 ⟶ 63:
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
 
Line 113 ⟶ 120:
else
return p._order(input_number)
end
end
 
Line 135 ⟶ 142:
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);
Line 144 ⟶ 154:
return math.log10(denom_value);
end
end
end
end
end
 
input_number, input_string = p._cleanNumber(input_string);
Line 153 ⟶ 163:
else
return p._precision(input_string)
end
end
 
Line 170 ⟶ 180:
x = string.sub(x, 1, exponent_pos - 1)
result = result - tonumber(exponent)
end
 
if decimal ~= nil then
Line 188 ⟶ 198:
return result
end
 
 
--[[
Line 205 ⟶ 216:
 
function p._max(...)
local max_value = binary_fold((function(a, b) return a > b end), ...)
local function maxOfTwo(a, b)
if a > b then
return a
else
return b
end
end
local max_value = applyFuncToArgs(maxOfTwo, ...)
if max_value then
return max_value
Line 219 ⟶ 223:
 
--[[
median
min
 
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
Line 237 ⟶ 272:
 
function p._min(...)
local min_value = binary_fold((function(a, b) return a < b end), ...)
local function minOfTwo(a, b)
if a < b then
return a
else
return b
end
end
local min_value = applyFuncToArgs(minOfTwo, ...)
if min_value then
return min_value
Line 251 ⟶ 279:
 
--[[
sum
average
 
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
Line 268 ⟶ 322:
 
function p._average(...)
local functionsum, getSumcount = fold((function(a, b) return a + b end), ...)
return a + b
end
local sum, count = applyFuncToArgs(getSum, ...)
if not sum then
return 0
Line 296 ⟶ 347:
else
return p._round(value, precision)
end
end
 
Line 302 ⟶ 353:
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
 
Line 323 ⟶ 387:
else
return p._mod(x, y)
end
end
 
Line 360 ⟶ 424:
return oldr
end
local result, count = applyFuncToArgsfold(findGcd, ...)
return result
end
Line 367 ⟶ 431:
precision_format
 
Rounds a number to the specified precision and formats according to rules
originally used for {{template:Rnd}}. Output is a string.
 
Line 399 ⟶ 463:
-- some circumstances because the terminal digits will be inaccurately reported.
if order + precision >= 14 then
orig_precisionif =order + p._precision(value_string) >= 14 then
precision = 13 - order;
if order + orig_precision >= 14 then
end
precision = 13 - order;
end
end
 
Line 409 ⟶ 472:
value = p._round(value, precision)
current_precision = p._precision(value)
end
 
local formatted_num = lang:formatNum(math.abs(value))
Line 419 ⟶ 482:
else
sign = ''
end
 
-- Handle cases requiring scientific notation
Line 428 ⟶ 491:
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
Line 446 ⟶ 509:
 
formatted_num = formatted_num .. string.rep('0', padding)
end
else
padding = precision - current_precision
if padding > 20 then
Line 463 ⟶ 526:
else
order = lang:formatNum(order)
end
 
formatted_num = formatted_num .. '<span style="margin:0 .15em 0 .25em">×</span>10<sup>' .. order .. '</sup>'
Line 472 ⟶ 535:
 
--[[
divide
Helper function that interprets the input numerically. If the
 
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.
Line 491 ⟶ 603:
-- If failed, attempt to evaluate input as an expression
if number == nil then
local success, result = pcall(mw.ext.ParserFunctions.expr, number_string)
local frame = mw.getCurrentFrame()
if success then
local attempt = frame:callParserFunction('#expr', number_string)
attempt number = tonumber(attemptresult)
if attempt ~= nil then
number = attempt
number_string = tostring(number)
else
Line 518 ⟶ 628:
]]
 
local mt = { __index = function(t, k)
local function makeWrapper(funcName)
return function (frame)
if not getArgs then
local args = getArgs(frame) -- Argument processing is left to Module:Arguments. Whitespace is trimmed and blank arguments are removed.
getArgs = require('Module:Arguments').getArgs
return wrap[funcName](args)
end
return wrap[k](getArgs(frame)) -- Argument processing is left to Module:Arguments. Whitespace is trimmed and blank arguments are removed.
end
end }
 
for funcName in pairs(wrap) do
p[funcName] = makeWrapper(funcName)
end
 
return setmetatable(p, mt)