Module:Roman
-- This module implements {{Roman}}.
 
 local p = {}
 
 -- This function implements the {{overline}} template.
 local function overline(s)
     return mw.ustring.format( '&lt;span style=&quot;text-decoration:overline;&quot;&gt;%s&lt;/span&gt;', s )
 end
 
 -- Gets the Roman numerals for a given numeral table. Returns both the string of
 -- numerals and the value of the number after it is finished being processed.
 local function getLetters(num, t)
     local ret = {}
     for _, v in ipairs(t) do
         local val, letter = unpack(v)
         while num &gt;= val do
             num = num - val
             table.insert(ret, letter)
         end
     end
 
     return table.concat(ret), num
 end
 
 -- The main control flow of the module.
 local function _main(args)
     -- Get input and exit displaying nothing if the input is empty.
     if args[1] == nil then return end
     local num = tonumber(args[1])
     if not num or num &lt; 0 or num == math.huge then
     	error('Invalid number ' .. args[1], 2)
     elseif num == 0 then
         return 'N'
     end
 
     -- Return a message for numbers too big to be expressed in Roman numerals.
     if num &gt;= 5000000 then
         return args[2] or 'N/A'
     end
 
     local ret = ''
     -- Find the Roman numerals for the large part of numbers.
     -- 23 April 2016 - tweaked to &gt;= 4000 to accept big Roman 'IV'
     -- The if statement is not strictly necessary, but makes the algorithm 
     -- more efficient for smaller numbers.
     if num &gt;= 4000 then
         local bigRomans = {
             { 1000000, 'M' },
             { 900000, 'CM' }, { 500000, 'D' }, { 400000, 'CD' }, { 100000, 'C' },
             {  90000, 'XC' }, {  50000, 'L' }, {  40000, 'XL' }, {  10000, 'X' },
             {   9000, 'IX' }, {   5000, 'V' }, {   4000, 'IV' },
         }
         local bigLetters
         bigLetters, num = getLetters(num, bigRomans)
         ret = overline(bigLetters)
     end
 
     -- Find the Roman numerals for numbers less than the big Roman threshold.
     local smallRomans = {
         { 1000, 'M' },
         { 900, 'CM' }, { 500, 'D' }, { 400, 'CD' }, { 100, 'C' },
         {  90, 'XC' }, {  50, 'L' }, {  40, 'XL' }, {  10, 'X' },
         {   9, 'IX' }, {   5, 'V' }, {   4, 'IV' }, {   1, 'I' }
     }
     local smallLetters = getLetters( num, smallRomans )
     ret = ret .. smallLetters
 
     if args.fraction == 'yes' then
         -- Find the Roman numerals for the fractional parts of numbers.
         -- If num is not a whole number, add half of 1/1728 (the smallest unit) to equate to rounding.
         -- Ensure we're not less than the smallest unit or larger than 1 - smallest unit
         -- to avoid getting two &quot;half&quot; symbols or no symbols at all
         num = num - math.floor(num)
         if num ~= 0 then
             num = math.max(1.1/1728, math.min(1727.1/1728, num + 1/3456))
         end
         local fractionalRomans = {
             { 1/2, 'S' }, { 5/12, &quot;''':'''•''':'''&quot; }, { 1/3, &quot;'''::'''&quot; },
             { 1/4, &quot;''':'''•&quot; }, { 1/6, &quot;''':'''&quot; }, { 1/12, '•' },
             { 1/24, 'Є' }, { 1/36, 'ƧƧ' }, { 1/48, 'Ɔ' }, { 1/72, 'Ƨ' }, { 1/144, '&lt;s&gt;Ƨ&lt;/s&gt;' },
             { 1/288, '℈' }, { 1/1728, '»' },
         }
         local fractionalLetters = getLetters(num, fractionalRomans)
         
         ret = ret .. fractionalLetters
     end
 
     return ret
 end
 
 function p.main(frame)
     -- If called via #invoke, use the args passed into the invoking
     -- template, or the args passed to #invoke if any exist. Otherwise
     -- assume args are being passed directly in from the debug console
     -- or from another Lua module.
     local origArgs
     if frame == mw.getCurrentFrame() then
         origArgs = frame:getParent().args
         for k, v in pairs(frame.args) do
             origArgs = frame.args
             break
         end
     else
         origArgs = frame
     end
     -- Trim whitespace and remove blank arguments.
     local args = {}
     for k, v in pairs(origArgs) do
         if type( v ) == 'string' then
             v = mw.text.trim(v)
         end
         if v ~= '' then
             args[k] = v
         end
     end
     
     -- exit if not given anything
     if args == nil or args == {} then return end
     -- Given mathematical expression, simplify to a number
     if type(args[1]) == 'string' then
         args[1] = mw.ext.ParserFunctions.expr(args[1])
     end
     return _main(args)
 end