Módulo:Roman
Aspeto
Este módulo implementa a predefinição {{Roman}}. Para a documentação comportamental, ver a página da predefinição. Para casos de teste, ver Predefinição:Roman/Exemplos para testes.
- O módulo suporta 0 como um numeral romano, exibido como "N".
- Antes de 25 de abril de 2016, era usado para exibir 69105 como LXVMMMMCV. Com a adição de IX e IV sendo 9000 e 4000 respectivamente, agora exibimos 69105 como LXIXCV.
- O módulo lida com expressões decimais, fracionárias e aritméticas com uma precisão de 1/1728. Usa
#expr:
na linha 126.
Lidando com casos complicados (como 0,00001 e 99,99999)
[editar código-fonte]- Encontre os algarismos romanos para a parte inteira do número.
- Se o número não for um inteiro:
- Adicione metade da menor unidade (1/1728) para simular arredondamento em vez de truncamento.
- Certifique-se de que este novo resultado esteja entre 1/1728 e 1727/1728. (na verdade 1,1/1728 e 1727,1/1728 devido a problemas de arredondamento de ponto flutuante)
- Portanto, é garantido que 0,00001 tenha pelo menos o menor símbolo de unidade (em vez de estar em branco ou 0) e 99,99999 não é exibido como 100 ou 99 e 2 metades.
Validação
[editar código-fonte]- Predefinição:Roman/Exemplos para testes
- Módulo:Roman/Exemplos para testes - não contém testes fracionários/decimais
- A predefinição suporta
subst:
esafesubst:
.
-- Este módulo implementa {{Roman}}.
require[[strict]]
local p = {}
-- Esta função implementa, internamente, a predefinição {{Sobrelinhado}}.
local function overline(s)
return mw.ustring.format( '<span style="text-decoration:overline;">%s</span>', s )
end
-- Obtém os numerais romanos para uma determinada tabela numeral. Retorna tanto
-- a sequência ('string') de numerais e o valor do número depois que ele
-- terminar de ser processado.
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
-- O fluxo de controle principal do módulo.
local function _main(args)
-- Obtém a entrada e sai sem exibir nada se a entrada estiver vazia.
if args[1] == nil then return end
local num = tonumber(args[1])
if not num or num < 0 or num == math.huge then
error('Número inválido ' .. args[1], 2)
elseif num == 0 then
return 'N'
end
-- Retorna uma mensagem para números muito grandes para serem expressos
-- em algarismos romanos.
if num >= 5000000 then
return args[2] or 'N/A'
end
local ret = ''
-- Encontra os algarismos romanos para a maior parte dos números.
-- 23 de abril de 2016 - ajustado para >= 4000 para aceitar o romano "IV" grande
-- A instrução "if" não é estritamente necessária, mas torna o algoritmo
-- mais eficiente para números menores.
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
-- Encontra os numerais romanos para números menores que o limite romano grande.
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
-- Encontra os numerais romanos para as partes fracionárias dos números.
-- Se num não for um número inteiro, adiciona a metade de 1/1728
-- (a menor unidade) para igualar ao arredondamento.
-- Certifica-se de que não somos menores que a menor unidade ou maiores
-- que 1 - a menor unidade para evitar obter dois símbolos "meio"
-- ou nenhum símbolo
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, '<s>Ƨ</s>' },
{ 1/288, '℈' }, { 1/1728, '»' },
}
local fractionalLetters = getLetters(num, fractionalRomans)
ret = ret .. fractionalLetters
end
return ret
end
function p.main(frame)
-- Se chamado via "#invoke", usa os argumentos passados na chamada da
-- predefinição, ou os argumentos passados para "#invoke" se existirem.
-- De outra forma assume que os argumentos estão sendo passados diretamente
-- do console de depuração ou de outro módulo Lua.
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
-- Corta os espaços em branco e remove os argumentos em branco.
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
-- Saída se não for dado nada.
if args == nil or args == {} then return end
-- Dada a expressão matemática, simplifica para um número.
if type(args[1]) == 'string' then
local success, result = pcall(mw.ext.ParserFunctions.expr, args[1])
if success then
args[1] = result
end -- Caso não, passa para a rotina "_main" e tenta deixar a "tonumber"
-- de Lua lidar com isso.
end
return _main(args)
end
return p