Editing Module:Math
From MINR.ORG WIKI
Warning: You are not logged in. Your IP address will be publicly visible if you make any edits. If you log in or create an account, your edits will be attributed to your username, along with other benefits.
The edit can be undone.
Please check the comparison below to verify that this is what you want to do, and then save the changes below to finish undoing the edit.
Latest revision | Your text | ||
Line 1: | Line 1: | ||
− | + | local z = {} | |
+ | require( "mw.language" ); | ||
− | + | -- Clean numeric value | |
− | + | function z._cleanNumber( frame, number_string ) | |
− | + | if number_string == nil or number_string:len() == 0 then | |
− | + | return nil, nil; | |
− | + | end | |
− | + | ||
− | + | -- Attempt basic conversion | |
− | + | local number = tonumber( number_string ) | |
− | + | ||
− | + | -- If failed, attempt to evaluate input as an expression | |
− | + | if number == nil then | |
− | + | local attempt = frame:preprocess( '{{#expr: ' .. number_string .. '}}' ); | |
− | + | attempt = tonumber( attempt ); | |
− | + | if attempt ~= nil then | |
− | + | 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 | |
− | + | ||
− | + | return number, number_string; | |
− | |||
− | |||
− | |||
− | local | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | end | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | end | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
end | end | ||
− | -- | + | -- Generate random number |
− | + | function z.random( frame ) | |
− | + | first = tonumber(frame.args[1]) -- if it doesn't exist it's NaN, if not a number it's nil | |
− | Generate | + | second = tonumber(frame.args[2]) |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | function | ||
− | |||
− | |||
− | |||
− | |||
− | + | if first then -- if NaN or nil, will skip down to final return | |
− | + | if first <= second then -- could match if both nil, but already checked that first is a number in last line | |
− | + | return math.random(first, second) | |
− | + | end | |
− | + | return math.random(first) | |
− | + | end | |
− | + | return math.random() | |
− | |||
− | |||
− | |||
− | |||
− | |||
end | end | ||
− | -- | + | -- Determine order of magnitude |
− | + | function z.order(frame) | |
− | + | local input_string = (frame.args[1] or frame.args.x or '0'); | |
− | Determine order of magnitude | + | local input_number; |
− | + | ||
− | + | input_number = z._cleanNumber( frame, input_string ); | |
− | + | if input_number == nil then | |
− | + | return '<strong class="error">Formatting error: Order of magnitude input appears non-numeric</strong>' | |
− | + | else | |
− | function | + | return z._order( input_number ) |
− | + | end | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
end | end | ||
− | + | function z._order(x) | |
− | function | + | if x == 0 then return 0 end |
− | + | return math.floor(math.log10(math.abs(x))) | |
− | |||
end | end | ||
− | -- | + | -- Determines precision of a number using the string representation |
− | + | function z.precision( frame ) | |
− | + | local input_string = (frame.args[1] or frame.args.x or '0'); | |
− | + | local input_number; | |
− | + | ||
− | + | input_number, input_string = z._cleanNumber( frame, input_string ); | |
− | + | if input_string == nil then | |
− | + | return '<strong class="error">Formatting error: Precision input appears non-numeric</strong>' | |
− | + | else | |
− | function | + | return z._precision( input_string ) |
− | + | end | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
end | end | ||
+ | function z._precision( x ) | ||
+ | x = string.upper( x ) | ||
− | + | local decimal = string.find( x, '.', 1, true ) | |
− | + | local exponent_pos = string.find( x, 'E', 1, true ) | |
− | + | 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 | end | ||
− | + | -- Finds maximum argument | |
− | -- | + | function z.max( frame ) |
− | max | + | local args = frame.args; |
− | + | ||
− | + | if args[1] == nil then | |
− | + | local parent = frame:getParent(); | |
− | + | args = parent.args; | |
− | + | end | |
− | + | local max_value = nil; | |
− | + | ||
− | ] | + | local i = 1; |
− | + | while args[i] ~= nil do | |
− | + | local val = z._cleanNumber( frame, args[i] ); | |
− | + | if val ~= nil then | |
+ | if max_value == nil or val > max_value then | ||
+ | max_value = val; | ||
+ | end | ||
+ | end | ||
+ | i = i + 1; | ||
+ | end | ||
+ | |||
+ | return max_value | ||
end | end | ||
− | function | + | -- Finds minimum argument |
− | + | function z.min( frame ) | |
− | + | local args = frame.args; | |
− | + | ||
− | + | if args[1] == nil then | |
+ | local parent = frame:getParent(); | ||
+ | args = parent.args; | ||
+ | end | ||
+ | local min_value = nil; | ||
+ | |||
+ | local i = 1; | ||
+ | while frame.args[i] ~= nil do | ||
+ | local val = z._cleanNumber( frame, frame.args[i] ); | ||
+ | if val ~= nil then | ||
+ | if min_value == nil or val < min_value then | ||
+ | min_value = val; | ||
+ | end | ||
+ | end | ||
+ | i = i + 1; | ||
+ | end | ||
+ | |||
+ | return min_value | ||
end | end | ||
− | -- | + | -- Rounds a number to specified precision |
− | + | function z.round(frame) | |
− | + | local value, precision; | |
− | + | ||
− | + | value = z._cleanNumber( frame, frame.args[1] or frame.args.value or 0 ); | |
− | + | precision = z._cleanNumber( frame, frame.args[2] or frame.args.precision or 0 ); | |
− | + | ||
− | + | if value == nil or precision == nil then | |
− | + | return '<strong class="error">Formatting error: Round input appears non-numeric</strong>' | |
− | + | else | |
− | + | return z._round( value, precision ); | |
− | frame. | + | end |
− | |||
− | |||
− | |||
− | |||
end | end | ||
− | + | function z._round( value, precision ) | |
− | function | + | local rescale = math.pow( 10, precision ); |
− | + | return math.floor( value * rescale + 0.5 ) / rescale; | |
− | |||
− | |||
− | |||
end | end | ||
− | --[[ | + | -- Rounds a number to the specified precision and formats according to rules |
− | + | -- originally used for {{template:Rnd}}. Output is a string. | |
− | + | function z.precision_format( frame ) | |
− | + | -- For access to Mediawiki built-in formatter. | |
+ | local lang = mw.getContentLanguage(); | ||
+ | |||
+ | local value_string, value, precision; | ||
+ | value, value_string = z._cleanNumber( frame, frame.args[1] or 0 ); | ||
+ | precision = z._cleanNumber( frame, frame.args[2] or 0 ); | ||
+ | |||
+ | -- Check for non-numeric input | ||
+ | if value == nil or precision == nil then | ||
+ | return '<strong class="error">Formatting error: invalid input when rounding</strong>' | ||
+ | end | ||
+ | |||
+ | local current_precision = z._precision( value ); | ||
− | + | local order = 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. | |
+ | if order + precision >= 14 then | ||
+ | orig_precision = z._precision( value_string ); | ||
+ | if order + orig_precision >= 14 then | ||
+ | precision = 13 - order; | ||
+ | end | ||
+ | end | ||
− | + | -- If rounding off, truncate extra digits | |
− | + | if precision < current_precision then | |
+ | value = z._round( value, precision ); | ||
+ | current_precision = z._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 | |
− | end | + | 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 | end | ||
− | + | return z | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− |