Module:MathRoman

From Wikipedia

Documentation for this module may be created at Module:MathRoman/doc

--[[
Ce Module:MathRoman :
    convertit des nombres entiers en nombres romains et vice-versa,
	génère des erreurs précises sur le nombre entré,
	génère des erreurs sur les limites de conversion,
	permet d'afficher des tests de ces fonctions.
]]--

local p = {}

function p.erreur_color(t)
	return '<span style="color:red;" >' .. tostring(t) .. '</span>'
end

function p.roman2int(rm, err)
	if ( rm == nil ) then rm = '' end 
	if ( err == nil ) then err = '' end 
	if ( rm == '' ) then return '' end 
	local v = 0 -- valeur totale
	local v1 = 0 -- valeur de derniere lettre
	local v2 = 0 -- valeur de lettre precedente
	local v3 = 0 -- valeur de lettre precedente
	local x = '-' -- caractere en cours d'evaluation
	local i = 0 -- numéro du caractere en cours d'evaluation
	local j = 0 -- numéro du caractere de reference courant (debut en Lua)
	local k = 0 -- numéro du caractere de reference courant (fin en Lua)
	local e0 = '' -- texte d'erreur
	local e1 = '' -- texte d'erreur
	local e2 = '' -- texte d'erreur
	local e3 = '' -- texte d'erreur
	local e4 = '' -- texte d'erreur
	local lst = '-MDCLXVIJ' -- caracteres autorises
	while (x ~= '') do
		v3 = v2
		v2 = v1
		v1 = 0
		x = string.sub(rm, i, i)
		if ( x == 'M' ) then v1 = 1000 end
		if ( x == 'D' ) then v1 = 500 end
		if ( x == 'C' ) then v1 = 100 end
		if ( x == 'L' ) then v1 = 50 end
		if ( x == 'X' ) then v1 = 10 end
		if ( x == 'V' ) then v1 = 5 end
		if ( x == 'I' ) then v1 = 1 end
		if ( x == 'J' ) then
		v1 = 1
		if ( i < ( string.len(rm) - 0 ) )
		then e4 = ' erreur caractere J avant la fin.' end
		end
		v = v + v1
		if ( (v1 == 5*v2) or (v1 == 10*v2) ) then v = v - (2*v2) end -- ajuster 4, 9, 40, 90 ...
		j, k = string.find(lst, x)
		if ( j == nil ) then j = -1 end 
		if ( k == nil ) then k = -1 end 
		if ( j < 1 ) then e3 = ' erreur caractere '..x..' en '..i..'.' end
		if ( (v1 > v2) and (v2 > v3) ) then e2 = ' caracteres croissants.' end
		i = i + 1
		x = string.sub(rm, i, i)
	end
	if ( v == 0 ) then e0 = ' valeur nulle.' end
	if ( v > 4999 ) then e1 = ' valeur > 4999.' end
	if ( ( e0..e1..e2..e3..e4 > '' ) and ( err > '' ) ) then 
		err = ''..err..e0..e1..e2..e3..e4 -- sortie avec les erreurs
	else
		err = '' -- sortie sans les erreurs
	end
	return v, err -- avec ou sans erreurs
end -- function p.roman2int(rm, err)

function p.romani2r(i, j)
	if ( j == nil ) then j = '' end
	local rm=''
	if ( i == 1000 ) then rm = 'M' end
	if ( i == 500 ) then rm = 'D' end
	if ( i == 100 ) then rm = 'C' end
	if ( i == 50 ) then rm = 'L' end
	if ( i == 10 ) then rm = 'X' end
	if ( i == 5 ) then rm = 'V' end
	if ( i == 1 ) then 
		rm = 'I'
		if ( j == 'J' ) then  rm = 'J' end
	end
	return rm
end -- function p.romani2r(i, j)

function p.int2roman(i, err)
	local n = 0
	if ( i == nil ) then n = 0 else n = i end -- anti null
	if ( type(n) ~= 'number' ) then n = tonumber(n) end
	if ( type(n) ~= 'number' ) then n = 0 end
	n = math.floor(n) -- input:89: bad argument #1 to 'floor' (number expected, got nil)
	-- if ( type (v) ~= 'number' ) then i = 0 end -- anti nil
	-- i = i.valueOf()
	if ( err == nil ) then err = ' ' end -- anti null, to text
	local v100 = 100 
	local v500 = v100*5 
	local v1000 = v100*10 -- cycle romain 1000, 100, 10, 1
	local v=0 
	local v1=0 
	local v2=0 
	local v3=0 -- valeurs totale, derniere, et precedentes
	local reste=0 
	local reduction=0 -- reste a convertir, derniere reduction
	--local x='-' local i=0 -- caractere courant et son numéro
	--local lst='-MDCLXVIJ' -- liste des chiffres romains
	local rm='' 
	local roman='' -- chiffre et nombre romain resultant
	local e0='' 
	local e1='' 
	local e2='' 
	local e3='' 
	local e4='' -- erreurs detectables
	if ( n > 4999 ) then
		e1 = ' valeur > 4999.'
		roman = 'ERREUR'
		n = 0
	end 
	if ( n < 1 ) then
		e2 = ' valeur < 1.'
		roman = 'ERREUR'
		n = 0
	end 
	reste = n
	-- return ' test ' -- temporaire
	while (reste > 0) do
		v3 = v2 
		v2 = v1 
		v1 = reste
		reduction = 0
		if ( reste >= v1000 ) then 
			reduction = v1000 
		elseif ( reste >= v100*9 ) then 
			reduction = v100 
			reste = reste + v100*2 
		elseif ( reste >= v500 ) then 
			reduction = v500 
		elseif ( reste >= v100*4 ) then 
			reduction = v100 
			reste = reste + v100*2 
		elseif ( reste >= v100 ) then 
			reduction = v100 
		elseif ( reste >= 1000 ) then 
			v100 = 100 
			v1000 = 1000 
			reduction = v1000 
		end
		rm = p.romani2r(reduction)
		roman = roman..rm
		reste = reste - reduction
		if ( reste < v100 ) then 
			if ( v100 >= 10 ) then 
			v100 = v100/10 
			v500 = v100*5 
			v1000 = v100*10
			end
		end
	end
	-- if ( v == 0 ) then e0 = ' valeur nulle.' end
	-- if ( v > 4999 ) then e1 = ' valeur > 4999.' end
	if ( ( e0..e1..e2..e3..e4 > '' ) and ( err > '' ) ) then 
		err = ''..err..e0..e1..e2..e3..e4 -- sortie avec les erreurs
	else
		err = '' -- sortie sans les erreurs
	end
	return roman, err -- avec ou sans erreurs
end -- function p.int2roman(in, err)

function p.testerUnRomain(r1, view) 
	if ( r1 == nil ) then r1 = '' end
	if ( view == nil ) then view = '' end
	if ( view == '' ) then view = '%s' end
	local i, erri = p.roman2int(r1, ' Erreur r2i : ')
	local rm, errm = p.int2roman(i, ' Erreur i2r : ')
	local s = r1 .. " = '''" .. i .. "''' = " .. rm .. " "
	if ( erri == nil ) then erri = '' end
	if ( errm == nil ) then errm = '' end
	if ( ( erri ~= '' ) or ( errm ~= '' ) ) then
		s = s .. " -> " .. p.erreur_color( erri ) .. " '''-''' " .. p.erreur_color( errm )
	end
	return string.format(view, s)
	-- return string.format("Hello, %s!", s)
end -- function p.testerUnRomain(r1, view)

function p.erreurUnRomain(r1, view)
	if ( r1 == nil ) then r1 = '' end
	if ( view == nil ) then view = '' end
	if ( view == '' ) then view = '%s' end
	local i, erri = p.roman2int(r1, ' Erreur r2i : ')
	local s = " - " .. r1 .. " -> '''" .. i .. "''' "
	if ( erri == nil ) then erri = '' end
	if ( erri ~= '' ) then
		s = s .. ' -> ' .. p.erreur_color( erri )
	end
	
	return string.format(view, s)
	-- return string.format("Hello, %s!", s)
end -- function p.erreurUnRomain(r1, view)

function p.testerDesRomains(view)
	if ( view == nil ) then view = '' end
	if ( view == '' ) then view = '%s' end
	view = '\n* %s'
	local s = ''
	s = s .. "\n;Tests sans erreurs :"
	s = s .. p.testerUnRomain('XIJ', view)
	s = s .. p.testerUnRomain('XIJ', view)
	s = s .. p.testerUnRomain('MCXI', view)
	s = s .. p.testerUnRomain('MCDXLIV', view)
	s = s .. p.testerUnRomain('MDCLXVI', view)
	s = s .. p.testerUnRomain('MCMXCIX', view)
	s = s .. p.testerUnRomain('MMCCXXII', view)
	s = s .. p.testerUnRomain('MMMMCMXCIX', view)
	s = s .. "\n;Tests avec erreurs :"
	s = s .. p.testerUnRomain('i', view)
	s = s .. p.testerUnRomain('XIA', view)
	s = s .. p.testerUnRomain('XJI', view)
	s = s .. p.testerUnRomain('IXC', view)
	s = s .. p.testerUnRomain('VLD', view)
	s = s .. p.testerUnRomain('', view)
	s = s .. p.testerUnRomain(nil)
	s = s .. p.erreurUnRomain('XIA', view)
	s = s .. p.erreurUnRomain('XJI', view)
	s = s .. p.erreurUnRomain('IXC', view)
	s = s .. p.erreurUnRomain('VLD', view)
	s = s .. "\n;Nombres hors limites :"
	s = s .. p.testerUnRomain('MMMMM', view)
	s = s .. p.testerUnRomain('MMMMMYJXC', view)
	s = s .. p.erreurUnRomain('MMMMM', view)
	s = s .. p.erreurUnRomain('MMMMMYJXC', view)
	s = s .. p.testerUnRomain('ERREURS', view)
	s = s .. p.erreurUnRomain('ERREURS', view)
	return s
end -- function p.testerDesRomains(view) 

--  p.testerDesRomains('x') -- lance le test

-- Interface http://scribunto.wmflabs.org/

------------------------------------------------------------
-- Tests internes. Internal tests.
------------------------------------------------------------

function p.roman2integer(frame)
	-- { {#invoke:MathRoman.lua|p.roman2integer| MMXIJ } }
	local r = frame.args[1]
	local i, erri = p.roman2int(r, ' Error r2i : ')
	return i
end

function p.r2i(frame) -- shortcut of p.roman2integer
	-- { {#invoke:MathRoman.lua|r2i| MMXIJ } }
	return p.roman2integer(frame)
end

function p.integer2roman(frame)
	-- { {#invoke:MathRoman.lua|integer2roman| 2012 } }
	local i = frame.args[1]
	local r, errr = p.int2roman(i, ' Error i2r : ')
	return r
end

function p.i2r(frame) -- shortcut of integer2roman
	-- { {#invoke:MathRoman.lua|i2r| MMXIJ } }
	return p.integer2roman(frame)
end

function p.testRomans(frame)
	-- { {#invoke:MathRoman.lua|testRomans|': %s<br/>'} }
	local view = frame.args[1]
	if ( view == nil ) then view = '' end
	if ( view == '' ) then view = '%s' end
	local s = p.testerDesRomains(view)
	return s
end

function p.autotests(frame)
	-- { {#invoke:MathRoman.lua|testRomans|': %s<br/>'} }
	local view = frame.args[1]
	if ( view == nil ) then view = '' end
	if ( view == '' ) then view = '%s' end
	local s = p.testerDesRomains(view)
	return s
end

function p.testText(formater, text, n)
	-- { {#invoke:MathRoman.lua|testText|': %s<br/>'|Text under test. |3} }
	local s = ''
	local N = tonumber(n)
	while ( N > 0 ) do
		s = s .. string.format(formater, text)
		N = N - 1
	end
	return s
end

return p