Oracle SQL, 456 bytes
select listagg((select listagg(l)within group(order by 1)from dual start with trunc((n-nvl(n-mod(n,p),0))/v)>0 connect by level<=trunc((n-nvl(n-mod(n,p),0))/v)))within group(order by v desc)from (select 2849n from dual)cross join(select 1000v,null p,'m'l from dual union select 500,1000,'d'from dual union select 100,500,'c'from dual union select 50,100,'l'from dual union select 10,50,'x'from dual union select 5,10,'v'from dual union select 1,5,'i'from dual)
Outputs:
mmdcccxxxxviiii
Please note the actual size of the line is 460bytes, because it includes the input number (2849).
Ungolfed:
select listagg(
(select listagg(l, '') within group(order by 1)
from dual
start with trunc((n-nvl(p*trunc(n/p),0))/v) > 0
connect by level <= trunc((n-nvl(p*trunc(n/p),0))/v) )
) within group(order by v desc)
from (select 2348 n
from dual
) cross join (
select 1000v, null p, 'm' l from dual union
select 500, 1000, 'd' from dual union
select 100, 500, 'c' from dual union
select 50, 100, 'l' from dual union
select 10, 50, 'x' from dual union
select 5, 10, 'v' from dual union
select 1, 5, 'i' from dual
)
How it works:
I calculate how many of each letter I need, by calculating the most I can get to with the higher value one (infinity for M), and then doing an integer division between the current letter's value and the result of that.
E.g. 2348, how many C
s do I need? trunc((2348-mod(2348,500))/100)
= 3.
Then, I listagg
that letter together 3 times (exploiting CONNECT BY
to generate the 3 rows I need).
Finally, I listagg
everything together.
Kinda bulky, but most of it is the select from dual
s in the conversion table and I can't really do much about that...
4 -> IIII
is9 -> VIIII
as well instead ofIX
? \$\endgroup\$VIIII
is the only allowed output for 9. \$\endgroup\$