Modul:Math
Tampilan
Dokumentasi untuk modul ini dapat dibuat diModul:Math/doc
--[[
This module provides a number of basic mathematical operations.
]]
localz={}
-- Generate random number
functionz.random(frame)
first=tonumber(frame.args[1])-- if it doesn't exist it's NaN, if not a number it's nil
second=tonumber(frame.args[2])
iffirstthen-- if NaN or nil, will skip down to final return
iffirst<=secondthen-- could match if both nil, but already checked that first is a number in last line
returnmath.random(first,second)
end
returnmath.random(first)
end
returnmath.random()
end
--[[
order
Determine order of magnitude of a number
Usage:
{{#invoke: Math | order | value }}
]]
functionz.order(frame)
localinput_string=(frame.args[1]orframe.args.xor'0');
localinput_number;
input_number=z._cleanNumber(frame,input_string);
ifinput_number==nilthen
return'<strong class= "error" >Formatting error: Order of magnitude input appears non-numeric</strong>'
else
returnz._order(input_number)
end
end
functionz._order(x)
ifx==0thenreturn0end
returnmath.floor(math.log10(math.abs(x)))
end
--[[
precision
Detemines the precision of a number using the string representation
Usage:
{{ #invoke: Math | precision | value }}
]]
functionz.precision(frame)
localinput_string=(frame.args[1]orframe.args.xor'0');
localtrap_fraction=frame.args.check_fractionorfalse;
localinput_number;
iftype(trap_fraction)=='string'then
trap_fraction=trap_fraction:lower();
iftrap_fraction=='false'ortrap_fraction=='0'or
trap_fraction=='no'ortrap_fraction==''then
trap_fraction=false;
else
trap_fraction=true;
end
end
iftrap_fractionthen
localpos=string.find(input_string,'/',1,true);
ifpos~=nilthen
ifstring.find(input_string,'/',pos+1,true)==nilthen
localdenominator=string.sub(input_string,pos+1,-1);
localdenom_value=tonumber(denominator);
ifdenom_value~=nilthen
returnmath.log10(denom_value);
end
end
end
end
input_number,input_string=z._cleanNumber(frame,input_string);
ifinput_string==nilthen
return'<strong class= "error" >Formatting error: Precision input appears non-numeric</strong>'
else
returnz._precision(input_string)
end
end
functionz._precision(x)
x=string.upper(x)
localdecimal=string.find(x,'.',1,true)
localexponent_pos=string.find(x,'E',1,true)
localresult=0;
ifexponent_pos~=nilthen
localexponent=string.sub(x,exponent_pos+1)
x=string.sub(x,1,exponent_pos-1)
result=result-tonumber(exponent)
end
ifdecimal~=nilthen
result=result+string.len(x)-decimal
returnresult
end
localpos=string.len(x);
whilex:byte(pos)==string.byte('0')do
pos=pos-1
result=result-1
ifpos<=0then
return0
end
end
returnresult
end
--[[
max
Finds the maximum argument
Usage:
{{#invoke:Math| max | value1 | value2 |... }}
OR
{{#invoke:Math| max }}
When used with no arguments, it takes its input from the parent
frame. Note, any values that do not evaluate to numbers are ignored.
]]
functionz.max(frame)
localargs=frame.args;
ifargs[1]==nilthen
localparent=frame:getParent();
args=parent.args;
end
localmax_value=nil;
locali=1;
whileargs[i]~=nildo
localval=z._cleanNumber(frame,args[i]);
ifval~=nilthen
ifmax_value==nilorval>max_valuethen
max_value=val;
end
end
i=i+1;
end
returnmax_value
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.
]]
functionz.min(frame)
localargs=frame.args;
ifargs[1]==nilthen
localparent=frame:getParent();
args=parent.args;
end
localmin_value=nil;
locali=1;
whileargs[i]~=nildo
localval=z._cleanNumber(frame,args[i]);
ifval~=nilthen
ifmin_value==nilorval<min_valuethen
min_value=val;
end
end
i=i+1;
end
returnmin_value
end
--[[
average
Finds the average
Usage:
{{#invoke:Math| average | value1 | value2 |... }}
OR
{{#invoke:Math| average }}
When used with no arguments, it takes its input from the parent
frame. Note, any values that do not evaluate to numbers are ignored.
]]
functionz.average(frame)
localargs=frame.args;
ifargs[1]==nilthen
localparent=frame:getParent();
args=parent.args;
end
localsum=0;
localcount=0;
locali=1;
whileargs[i]~=nildo
localval=z._cleanNumber(frame,args[i]);
ifval~=nilthen
sum=sum+val
count=count+1
end
i=i+1;
end
return(count==0and0orsum/count)
end
--[[
round
Rounds a number to specified precision
Usage:
{{#invoke:Math | round | value | precision }}
--]]
functionz.round(frame)
localvalue,precision;
value=z._cleanNumber(frame,frame.args[1]orframe.args.valueor0);
precision=z._cleanNumber(frame,frame.args[2]orframe.args.precisionor0);
ifvalue==nilorprecision==nilthen
return'<strong class= "error" >Formatting error: Round input appears non-numeric</strong>'
else
returnz._round(value,precision);
end
end
functionz._round(value,precision)
localrescale=math.pow(10,precision);
returnmath.floor(value*rescale+0.5)/rescale;
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 }}
]]
functionz.precision_format(frame)
-- For access to Mediawiki built-in formatter.
locallang=mw.getContentLanguage();
localvalue_string,value,precision;
value,value_string=z._cleanNumber(frame,frame.args[1]or0);
precision=z._cleanNumber(frame,frame.args[2]or0);
-- Check for non-numeric input
ifvalue==nilorprecision==nilthen
return'<strong class= "error" >Formatting error: invalid input when rounding</strong>'
end
localcurrent_precision=z._precision(value);
localorder=z._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.
iforder+precision>=14then
orig_precision=z._precision(value_string);
iforder+orig_precision>=14then
precision=13-order;
end
end
-- If rounding off, truncate extra digits
ifprecision<current_precisionthen
value=z._round(value,precision);
current_precision=z._precision(value);
end
localformatted_num=lang:formatNum(math.abs(value));
localsign;
-- Use proper unary minus sign rather than ASCII default
ifvalue<0then
sign='−';
else
sign='';
end
-- Handle cases requiring scientific notation
ifstring.find(formatted_num,'E',1,true)~=nilormath.abs(order)>=9then
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
ifcurrent_precision<precisionthen
localpadding;
ifcurrent_precision<=0then
ifprecision>0then
localzero_sep=lang:formatNum(1.1);
formatted_num=formatted_num..zero_sep:sub(2,2);
padding=precision;
ifpadding>20then
padding=20;
end
formatted_num=formatted_num..string.rep('0',padding);
end
else
padding=precision-current_precision
ifpadding>20then
padding=20;
end
formatted_num=formatted_num..string.rep('0',padding);
end
end
-- Add exponential notation, if necessary.
iforder~=0then
-- Use proper unary minus sign rather than ASCII default
iforder<0then
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
returnformatted_num;
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.
]]
functionz._cleanNumber(frame,number_string)
ifnumber_string==nilornumber_string:len()==0then
returnnil,nil;
end
-- Attempt basic conversion
localnumber=tonumber(number_string)
-- If failed, attempt to evaluate input as an expression
ifnumber==nilthen
localattempt=frame:preprocess('{{#expr: '..number_string..'}}');
attempt=tonumber(attempt);
ifattempt~=nilthen
number=attempt;
number_string=tostring(number);
else
number=nil;
number_string=nil;
end
else
-- String is valid but may contain padding, clean it.
number_string=number_string:match("^%s*(.-)%s*$");
end
returnnumber,number_string;
end
returnz