Module:Roman Numeral
Jump to navigation
Jump to search
Documentation for this module may be created at Module:Roman Numeral/doc
local function split(source, sep)
local result = { [1] = '', [2] = '', [3] = '' }
local count = 1
for c in source:gmatch('.') do
if (c == sep) then
count = count + 1
end
if (result[count] == nil or result[count] == '') then
result[count] = c
else
result[count] = result[count] .. c
end
if (c == sep) then
count = count + 1
end
end
return result
end
local function join(intermediate, toJoin)
local result = ""
local len = #toJoin
local count = 1
for i, v in ipairs(toJoin) do
if (count >= len) then
result = result .. v
else
result = result .. v .. intermediate
end
count = count + 1
end
return result
end
local function createStringWithNZeroes(n)
local result = ""
for i=1, n do
result = result .. '0'
end
return result
end
function overline(s)
return mw.ustring.format( '<span style="text-decoration:overline;">%s</span>', s )
end
-- local function overline(s)
-- local str = ''
-- for c in s:gmatch('.') do
-- str = str .. c .. '\u{305}'
-- end
-- return str
-- end
local function truncate(f, n)
local s = tostring(f)
local Split = split(s, '.')
local decimal = Split[3] .. createStringWithNZeroes(n)
return tonumber(join('.',{ Split[1], decimal:sub(1, n) }))
end
function table.contains(Table, element)
for _, value in pairs(Table) do
if value == element then
return true
end
end
return false
end
function table.any(Table, TableToCompare)
for _, value in pairs(Table) do
for _, v in pairs(TableToCompare) do
if value == v then
return true
end
end
end
return false
end
function table.anyString(StringToCompare, Table)
for _, value in pairs(Table) do
for c in StringToCompare:gmatch('.') do
if value == c then
return true
end
end
end
return false
end
function table.slice(tbl, first, last, step)
local sliced = {}
for i = first or 1, last or #tbl, step or 1 do
sliced[#sliced+1] = tbl[i]
end
return sliced
end
local p = {}
local function _main(args)
local tensThou = {"", "ↂ", "ↂↂ", "ↂↂↂ", "ↂↇ", "ↇ", "ↇↂ", "ↇↂↂ", "ↇↂↂↂ", "ↂↈ"}
local thou = {"", "M", "MM", "MMM", "Mↁ", "ↁ", "ↁM", "ↁMM", "ↁMMM", "Mↂ"}
local huns = {"", "C", "CC", "CCC", "CD", "D", "DC", "DCC", "DCCC", "CM"}
local hunThou = {"", "ↈ", "ↈↈ", "ↈↈↈ", "ↈ" .. overline(huns[6]), overline(huns[6]), overline(huns[6]) .. "ↈ", overline(huns[6]) .. "ↈↈ", overline(huns[6]) .. "ↈↈ", "ↂ" .. overline(thou[2])}
local tensMil = {"", overline(tensThou[2]), overline(tensThou[2]) .. overline(tensThou[2]), overline(tensThou[2]) .. overline(tensThou[2]) .. overline(tensThou[2]), overline(tensThou[2]) .. overline(tensThou[6]), overline(tensThou[6]), overline(tensThou[6]) .. overline(tensThou[2]), overline(tensThou[6]) .. overline(tensThou[2]) .. overline(tensThou[2]), overline(tensThou[6]) .. overline(tensThou[2]) .. overline(tensThou[2]) .. overline(tensThou[2]), overline(tensThou[2]) .. overline(hunThou[2])}
local mils = {"", overline(thou[2]), overline(thou[2]) .. overline(thou[2]), overline(thou[2]) .. overline(thou[2]) .. overline(thou[2]), overline(thou[2]) .. overline(thou[6]), overline(thou[6]), overline(thou[6]) .. overline(thou[2]), overline(thou[6]) .. overline(thou[2]) .. overline(thou[2]), overline(thou[6]) .. overline(thou[2]) .. overline(thou[2]) .. overline(thou[2]), overline(thou[2]) .. overline(tensThou[2])}
local tens = {"", "X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC"}
local ones = {"", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX"}
local twelths = {"", "·", ":", "∴", "∷", "⁙", "S", "S·", "S:", "S∴", "S∷", "S⁙"}
local twentyFourths = {"", "Σ", "·", "·Σ", ":", ":Σ", "∴", "∴Σ", "∷", "∷Σ", "⁙", "ΣS", "S", "SΣ", "S·", "S·Σ", "S:", "S:Σ", "S:Σ", "S∴", "S∴Σ", "S∷", "S∷Σ", "S⁙", "S⁙Σ"}
local thirds = {truncate(1/3, 4), truncate(1/6, 4), truncate(2/3, 4), truncate(5/6, 4)}
local roman = ''
if args[1] == nil then return end
local num = tonumber(args[1])
if not num or num == math.huge then
return {'',''}
elseif num == 0 then
return {'N','\n0 is represented by N'}
elseif num < 0 then
roman = '-'
num = num - num*2
end
local explanation = "\n"
local count = 0
while num >= 100000000 do
roman = roman .. overline(hunThou[2])
num = num - 100000000
count = count + 1
end
if (count > 0) then
explanation = explanation .. tostring(count*100000000) .. " is represented by " .. roman .."\n"
end
roman = roman .. tensMil[1+math.floor(math.floor(tonumber(num))/10000000)]
if (num/10000000 >= 1) then
explanation = explanation .. tostring(math.floor(tonumber(num / 10000000))*10000000) .. " is represented by ".. tostring(tensMil[1+math.floor(math.floor(tonumber(num))/10000000)]) .."\n"
end
num = num % 10000000
roman = roman .. mils[1+math.floor(math.floor(tonumber(num))/1000000)]
if (num / 1000000 >= 1) then
explanation = explanation .. tostring(math.floor(math.floor(tonumber(num / 1000000))*1000000)) .. " is represented by " .. mils[1+math.floor(math.floor(tonumber(num)) / 1000000)] .."\n"
end
num = num % 1000000
roman = roman .. hunThou[1+math.floor(tonumber(math.floor(tonumber(num))/100000))]
if (num / 100000 >= 1) then
explanation = explanation .. tostring(math.floor(tonumber(math.floor(tonumber(num))/100000))*100000) .. " is represented by " .. hunThou[1+math.floor(tonumber(math.floor(tonumber(num))/100000))] .."\n"
end
num = num % 100000
roman = roman .. tensThou[1+math.floor(tonumber(math.floor(tonumber(num))/10000))]
if (num / 10000 >= 1) then
explanation = explanation .. tostring(math.floor(tonumber(math.floor(tonumber(num))/10000))*10000) .. " is represented by " .. tensThou[1+math.floor(tonumber(math.floor(tonumber(num))/10000))] .."\n"
end
num = num % 10000
roman = roman .. thou[1+math.floor(tonumber(math.floor(tonumber(num))/1000))]
if (num / 1000 >= 1) then
explanation = explanation .. tostring(math.floor(tonumber(math.floor(tonumber(num))/1000))*1000) .. " is represented by " .. thou[1+math.floor(tonumber(math.floor(tonumber(num))/1000))] .."\n"
end
num = num % 1000
roman = roman .. huns[1+math.floor(math.floor(tonumber(num))/100)]
if (num / 100 >= 1) then
explanation = explanation .. tostring(math.floor(math.floor(tonumber(num / 100))*100)) .. " is represented by " .. huns[1+math.floor(math.floor(tonumber(num)) / 100)] .."\n"
end
num = num % 100
roman = roman .. tens[1+math.floor(math.floor(tonumber(num))/10)]
if (num / 10 >= 1) then
explanation = explanation .. tostring(math.floor(math.floor(tonumber(num / 10))*10)) .. " is represented by " .. tens[1+math.floor(math.floor(tonumber(num)) / 10)] .."\n"
end
num = num % 10
roman = roman .. ones[1+math.floor(math.floor(tonumber(num)))]
if (num >= 1) then
explanation = explanation .. math.floor(tostring(math.floor(tonumber(num)))) .. " is represented by " .. ones[1+math.floor(math.floor(tonumber(num)))] .."\n"
end
num = num % 1
if not table.contains(thirds, truncate(num, 4)) then
roman = roman .. twelths[1+math.floor(tonumber(num/(1/12)))]
if table.anyString(roman, table.slice(twelths, 2)) then
explanation = explanation .. math.floor(tonumber(num / (1/12)))*(1/12) .. " is represented by ".. twelths[1+math.floor(tonumber(num/(1/12)))] .."\n"
end
num = num % (1/12)
roman = roman .. twentyFourths[1+math.floor(tonumber(num/(1/24)))]
if table.anyString(roman, table.slice(twentyFourths, 2)) and (math.floor(tonumber(num/(1/24)))*(1/24) ~= 0) then
explanation = explanation .. math.floor(tonumber(num/(1/24)))*(1/24) .. " is represented by ".. twentyFourths[1+math.floor(tonumber(num/(1/24)))] .."\n"
end
num = num % (1/24)
else
local number1 = truncate(num, 4)
if number1 == thirds[1] then
roman = roman .. twelths[6]
if table.anyString(roman, table.slice(twelths, 2)) then
explanation = explanation .. tostring(num) .. "is represented by " .. twelths[6] .. "\n"
end
elseif number1 == thirds[2] then
roman = roman .. twelths[4]
if table.anyString(roman, table.slice(twelths, 2)) then
explanation = explanation .. tostring(num) .. "is represented by " .. twelths[4] .. "\n"
end
elseif number1 == thirds[3] then
roman = roman .. twelths[9]
if table.anyString(roman, table.slice(twelths, 2)) then
explanation = explanation .. tostring(num) .. "is represented by " .. twelths[9] .. "\n"
end
elseif number1 == thirds[4] then
roman = roman .. twelths[11]
if table.anyString(roman, table.slice(twelths, 2)) then
explanation = explanation .. tostring(num) .. "is represented by " .. twelths[11] .. "\n"
end
end
end
return {roman, explanation}
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
local numExplanation = _main(args)
if numExplanation == nil or numExplanation == {} then return end
local res = ''
if args.explanation == "yes" then
for _, v in pairs(numExplanation) do
res = res .. v
end
return res
else
return numExplanation[1]
end
end
return p