Jump to content

Module:Roman: Difference between revisions

From Wikipedia, the free encyclopedia
Content deleted Content added
Reverted to revision 570926639 by Mr. Stradivarius (talk): For reference. (TW)
porting code over from sandbox
Line 4: Line 4:


-- This function implements the {{overline}} template.
-- This function implements the {{overline}} template.
local function overline( s )
local function overline(s)
return mw.ustring.format( '<span style="text-decoration:overline;">%s</span>', s )
return mw.ustring.format( '<span style="text-decoration:overline;">%s</span>', s )
end
end
Line 10: Line 10:
-- Gets the Roman numerals for a given numeral table. Returns both the string of
-- 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.
-- numerals and the value of the number after it is finished being processed.
local function getLetters( num, t )
local function getLetters(num, t)
local ret = {}
local ret = {}
for _, v in ipairs( t ) do
for _, v in ipairs(t) do
local val, letter = unpack( v )
local val, letter = unpack(v)
while num >= val do
while num >= val do
num = num - val
num = num - val
table.insert( ret, letter )
table.insert(ret, letter)
end
end
end
end

return table.concat( ret ), num
return table.concat(ret), num
end
end


-- The main control flow of the module.
-- The main control flow of the module.
local function _main( args )
local function _main(args)
-- Get input and exit displaying nothing if the input is bad.
-- Get input and exit displaying nothing if the input is bad.
local num = tonumber( args[ 1 ] )
local num = tonumber(args[1])
if not num or num < 1 or num == math.huge then
if not num or num < 0 or num == math.huge then
-- consider returning an error message here, like [[User:Stelio/Roman]]?
return
return
elseif num == 0 then
return 'N'
end
end

num = math.floor( num )
-- Return a message for numbers too big to be expressed in Roman numerals.
-- Return a message for numbers too big to be expressed in Roman numerals.
if num >= 5000000 then
if num >= 5000000 then
return args[ 2 ] or 'N/A'
return args[2] or 'N/A'
end
end

local ret = ''
local ret = ''
-- Find the Roman numerals for the large part of numbers 5000 and bigger.
-- Find the Roman numerals for the large part of numbers.
-- 23 April 2016 - tweaked to >= 4000 to accept big Roman 'IV'
-- The if statement is not strictly necessary, but makes the algorithm
-- The if statement is not strictly necessary, but makes the algorithm
-- more efficient for smaller numbers.
-- more efficient for smaller numbers.
if num >= 5000 then
if num >= 4000 then
local bigRomans = {
local bigRomans = {
{ 1000000, 'M' },
{ 1000000, 'M' },
{ 900000, 'CM' }, { 500000, 'D' }, { 400000, 'CD' }, { 100000, 'C' },
{ 900000, 'CM' }, { 500000, 'D' }, { 400000, 'CD' }, { 100000, 'C' },
{ 90000, 'XC' }, { 50000, 'L' }, { 40000, 'XL' }, { 10000, 'X' },
{ 90000, 'XC' }, { 50000, 'L' }, { 40000, 'XL' }, { 10000, 'X' },
{ 5000, 'V' }
{ 9000, 'IX' }, { 5000, 'V' }, { 4000, 'IV' },
}
}
local bigLetters
local bigLetters
bigLetters, num = getLetters( num, bigRomans )
bigLetters, num = getLetters(num, bigRomans)
ret = overline( bigLetters )
ret = overline(bigLetters)
end
end

-- Find the Roman numerals for numbers 4999 or less.
-- Find the Roman numerals for numbers less than the big Roman threshold.
local smallRomans = {
local smallRomans = {
{1000, "M"},
{ 1000, 'M' },
{900, "CM"}, {500, "D"}, {400, "CD"}, {100, "C"},
{ 900, 'CM' }, { 500, 'D' }, { 400, 'CD' }, { 100, 'C' },
{90, "XC"}, {50, "L"}, {40, "XL"}, {10, "X"},
{ 90, 'XC' }, { 50, 'L' }, { 40, 'XL' }, { 10, 'X' },
{9, "IX"}, {5, "V"}, {4, "IV"}, {1, "I"}
{ 9, 'IX' }, { 5, 'V' }, { 4, 'IV' }, { 1, 'I' }
}
}
local smallLetters = getLetters( num, smallRomans )
local smallLetters = getLetters( num, smallRomans )
ret = ret .. smallLetters
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 "half" 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, "''':'''•''':'''" }, { 1/3, "'''::'''" },
{ 1/4, "''':'''•" }, { 1/6, "''':'''" }, { 1/12, '•' },
{ 1/24, 'Є' }, { 1/36, 'ƧƧ' }, { 1/48, 'Ɔ' }, { 1/72, 'Ƨ' }, { 1/144, 'ƻ' },
{ 1/288, '℈' }, { 1/1728, '»' },
}
local fractionalLetters = getLetters(num, fractionalRomans)
ret = ret .. fractionalLetters
end

return ret
return ret
end
end


function p.main( frame )
function p.main(frame)
-- If called via #invoke, use the args passed into the invoking
-- If called via #invoke, use the args passed into the invoking
-- template, or the args passed to #invoke if any exist. Otherwise
-- template, or the args passed to #invoke if any exist. Otherwise
Line 73: Line 97:
if frame == mw.getCurrentFrame() then
if frame == mw.getCurrentFrame() then
origArgs = frame:getParent().args
origArgs = frame:getParent().args
for k, v in pairs( frame.args ) do
for k, v in pairs(frame.args) do
origArgs = frame.args
origArgs = frame.args
break
break
Line 82: Line 106:
-- Trim whitespace and remove blank arguments.
-- Trim whitespace and remove blank arguments.
local args = {}
local args = {}
for k, v in pairs( origArgs ) do
for k, v in pairs(origArgs) do
if type( v ) == 'string' then
if type( v ) == 'string' then
v = mw.text.trim( v )
v = mw.text.trim(v)
end
end
if v ~= '' then
if v ~= '' then
Line 90: Line 114:
end
end
end
end
return _main( args )
-- Given mathematical expression, simplify to a number
if args[1] then
args[1] = frame:callParserFunction('#expr', args[1])
end
return _main(args)
end
end



Revision as of 08:35, 25 April 2016

-- This module implements {{Roman}}.

local p = {}

-- This function implements the {{overline}} template.
local function overline(s)
    return mw.ustring.format( '<span style="text-decoration:overline;">%s</span>', 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 >= 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 bad.
    local num = tonumber(args[1])
    if not num or num < 0 or num == math.huge then
        -- consider returning an error message here, like [[User:Stelio/Roman]]?
        return
    elseif num == 0 then
        return 'N'
    end

    -- Return a message for numbers too big to be expressed in Roman numerals.
    if num >= 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 >= 4000 to accept big Roman 'IV'
    -- The if statement is not strictly necessary, but makes the algorithm 
    -- more efficient for smaller numbers.
    if num >= 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 "half" 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, "''':'''•''':'''" }, { 1/3, "'''::'''" },
            { 1/4, "''':'''•" }, { 1/6, "''':'''" }, { 1/12, '•' },
            { 1/24, 'Є' }, { 1/36, 'ƧƧ' }, { 1/48, 'Ɔ' }, { 1/72, 'Ƨ' }, { 1/144, 'ƻ' },
            { 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
    
    -- Given mathematical expression, simplify to a number
    if args[1] then
        args[1] = frame:callParserFunction('#expr', args[1])
    end
    return _main(args)
end

return p