Module:Math: Difference between revisions

2,014 bytes added ,  11 years ago
adds expression checking, more error messages, and better handling of some precision format cases, and precision flooding check
m>Dragons flight
m (fmt)
m>Dragons flight
(adds expression checking, more error messages, and better handling of some precision format cases, and precision flooding check)
Line 1: Line 1:
local z = {}
local z = {}
require( "mw.language" );
-- Clean numeric value
function z._cleanNumber( frame, number_string )
    -- 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;
end


-- Generate random number
-- Generate random number
Line 17: Line 42:
-- Determine order of magnitude
-- Determine order of magnitude
function z.order(frame)
function z.order(frame)
     return z._order(tonumber(frame.args[1] or frame.args.x or 0))
     local input_string = (frame.args[1] or frame.args.x or '0');
    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
        return z._order( input_number )
    end   
end
end
function z._order(x)
function z._order(x)
Line 26: Line 59:
-- Determines precision of a number using the string representation
-- Determines precision of a number using the string representation
function z.precision( frame )
function z.precision( frame )
     return z._precision( frame.args[1] or frame.args.x or '0' )
     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
        return z._precision( input_string )
    end   
end
end
function z._precision( x )
function z._precision( x )  
     x = string.upper( x )
     x = string.upper( x )
    -- Remove leading / trailing whitespace
    x = x:match "^%s*(.-)%s*$";


     local decimal = string.find( x, '.', 1, true )
     local decimal = string.find( x, '.', 1, true )
Line 66: Line 104:
         return ''
         return ''
     end
     end
     local max_value = tonumber( frame.args[1] )
     local max_value = nil;
      
      
     local i = 2;
     local i = 1;
     while frame.args[i] ~= nil do
     while frame.args[i] ~= nil do
         local val = tonumber( frame.args[i] );
         local val = z._cleanNumber( frame, frame.args[i] );
         if val ~= nil then
         if val ~= nil then
             if val > max_value then
             if max_value == nil or val > max_value then
                 max_value = val;
                 max_value = val;
             end
             end
Line 87: Line 125:
         return ''
         return ''
     end
     end
     local min_value = tonumber( frame.args[1] )
     local min_value = nil;
      
      
     local i = 2;
     local i = 1;
     while frame.args[i] ~= nil do
     while frame.args[i] ~= nil do
         local val = tonumber( frame.args[i] );
         local val = z._cleanNumber( frame, frame.args[i] );
         if val ~= nil then
         if val ~= nil then
             if val < min_value then
             if min_value == nil or val < min_value then
                 min_value = val;
                 min_value = val;
             end
             end
Line 105: Line 143:
-- Rounds a number to specified precision
-- Rounds a number to specified precision
function z.round(frame)
function z.round(frame)
     local value = tonumber(frame.args[1] or frame.args.value or 0);
     local value, precision;
     local precision = tonumber(frame.args[2] or frame.args.precision or 0);
   
     return z._round( 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 );
    end   
end
end
function z._round( value, precision )
function z._round( value, precision )
Line 120: Line 165:
     local lang = mw.getContentLanguage();
     local lang = mw.getContentLanguage();
      
      
     local value = tonumber( frame.args[1] or 0 );
     local value_string, value, precision;
     local precision = tonumber( frame.args[2] or 0 );
    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
     -- Check for non-numeric input
Line 135: Line 181:
     -- some circumstances because the terminal digits will be inaccurately reported.
     -- some circumstances because the terminal digits will be inaccurately reported.
     if order + precision >= 14 then
     if order + precision >= 14 then
         precision = 13 - order;         
         orig_precision = z._precision( value_string );
        if order + orig_precision >= 14 then
            precision = 13 - order;      
        end        
     end
     end


Line 165: Line 214:
     formatted_num = sign .. formatted_num;
     formatted_num = sign .. formatted_num;
      
      
     -- Pad with zeros, if needed
     -- Pad with zeros, if needed  
     if current_precision < precision then
     if current_precision < precision then
        local padding;
         if current_precision <= 0 then
         if current_precision <= 0 then
             if precision > 0 then
             if precision > 0 then
                 local zero_sep = lang:formatNum( 1.1 );
                 local zero_sep = lang:formatNum( 1.1 );
                 formatted_num = formatted_num .. zero_sep:sub(2,2);
                 formatted_num = formatted_num .. zero_sep:sub(2,2);
                 formatted_num = formatted_num .. string.rep( '0', precision );
 
                padding = precision;
                if padding > 20 then
                    padding = 20;
                end
               
                 formatted_num = formatted_num .. string.rep( '0', padding );
             end             
             end             
         else      
         else                  
             formatted_num = formatted_num .. string.rep( '0', precision - current_precision );
            padding = precision - current_precision
            if padding > 20 then
                padding = 20;
            end
             formatted_num = formatted_num .. string.rep( '0', padding );
         end
         end
     end
     end
Anonymous user