⍝ R o m a n N u m e r a l s See →notes.roman←
← .() ⍝ digit binding: 7 → V.I.I
⍴() ⍺() ⍝ Roman ←→ Arabic: C.X.L.I.X ←→ 1.4.9
← ×() ÷() %() ⍝ mul div rem
← +() -() ⍝ add sub
⍝ Pattern sets:
s p q r :: ⍝ match anything.
n m :: I V X L C D M ⍝ match single digit.
k :: absurdus nimius ⍝ too small, too big.
i :: nulla ⍝ nothing.
j :: I V X L C D M absurdus nulla nimius ⍝ any atomic value.
⍝ Auxiliary functions for expanded digit strings:
\() ⍝ expand (remove subtractive prefixes).
/() ⍝ compress (apply subtractive prefixes).
← ∘() ⍝ expanded digit separator (disables normalisation).
⍝ Add
p + q = /(\p ++ \q) ⍝ Add expanded digit strings.
← ++() ⍝ merge strings, preserving order.
p ++ k = k ⍝ special values.
k ++ p = k
i ++ q = q
p ++ i = p
p ++ I = p∘I ⍝ First, collect Is, then
I ++ q = q∘I
p ++ q∘I = (p ++ q)∘I
p∘I ++ q = (p ++ q)∘I
p ++ V = p∘V ⍝ collect Vs, then
V ++ q = q∘V
p ++ q∘V = (p ++ q)∘V
p∘V ++ q = (p ++ q)∘V
p ++ X = p∘X ⍝ collect Xs, then
X ++ q = q∘X
p ++ q∘X = (p ++ q)∘X
p∘X ++ q = (p ++ q)∘X
p ++ L = p∘L ⍝ collect Ls, then
L ++ q = q∘L
p ++ q∘L = (p ++ q)∘L
p∘L ++ q = (p ++ q)∘L
p ++ C = p∘C ⍝ collect Cs, then
C ++ q = q∘C
p ++ q∘C = (p ++ q)∘C
p∘C ++ q = (p ++ q)∘C
p ++ D = p∘D ⍝ collect Ds, then
D ++ q = q∘D
p ++ q∘D = (p ++ q)∘D
p∘D ++ q = (p ++ q)∘D
p ++ M = p∘M ⍝ collect Ms.
M ++ q = q∘M
p ++ q∘M = (p ++ q)∘M
p∘M ++ q = (p ++ q)∘M
⍝ Sub
p - q = /(\p -- \q) ⍝ Subtract expanded digit strings.
← --() ⍝ remove common digits.
V -- I = I∘I∘I∘I ⍝ sub I
X -- I = V∘I∘I∘I∘I
L -- I = X∘X∘X∘X∘V∘I∘I∘I∘I
C -- I = L∘X∘X∘X∘X∘V∘I∘I∘I∘I
D -- I = C∘C∘C∘C∘L∘X∘X∘X∘X∘V∘I∘I∘I∘I
M -- I = D∘C∘C∘C∘C∘L∘X∘X∘X∘X∘V∘I∘I∘I∘I
X -- V = V ⍝ sub V
L -- V = X∘X∘X∘X∘V
C -- V = L∘X∘X∘X∘X∘V
D -- V = C∘C∘C∘C∘L∘X∘X∘X∘X∘V
M -- V = D∘C∘C∘C∘C∘L∘X∘X∘X∘X∘V
L -- X = X∘X∘X∘X ⍝ sub X
C -- X = L∘X∘X∘X∘X
D -- X = C∘C∘C∘C∘L∘X∘X∘X∘X
M -- X = D∘C∘C∘C∘C∘L∘X∘X∘X∘X
C -- L = L ⍝ sub L
D -- L = C∘C∘C∘C∘L
M -- L = D∘C∘C∘C∘C∘L
D -- C = C∘C∘C∘C ⍝ sub C
M -- C = D∘C∘C∘C∘C
M -- D = D∘C∘C∘C∘C ⍝ sub D
p∘m -- m = p ⍝ subtract multi-digit nos.
p -- q∘m = p -- q -- m
p∘m -- r = (p -- r) ++ m
(p--p)∘m = m
m -- m = nulla ⍝ nothing left.
m -- n = absurdus ⍝ less than nothing left.
p -- i = p ⍝ special values.
i -- q = absurdus
p -- k = absurdus
k -- q = k
⍝ Mul
p × q = /(\p ×× \q) ⍝ Multiply expanded digit strings.
← ××() ⍝ auxiliary function.
p ×× I = p ⍝ I × ···
I ×× q = q ⍝ ··· × I
V ×× V = X∘X∘V ⍝ V × ···
V ×× X = L
V ×× L = C∘C∘L
V ×× C = D
V ×× D = M∘M∘D
X ×× V = L ⍝ X × ···
X ×× X = C
X ×× L = D
X ×× C = M
L ×× V = C∘C∘L ⍝ L × ···
L ×× X = D
L ×× L = M∘M∘D
C ×× V = D ⍝ C × ···
C ×× X = M
D ×× V = M∘M∘D ⍝ D × ···
i ×× q = i ⍝ special values
p ×× i = i
k ×× q = k
p ×× k = k
p∘m ×× q∘n = (p××q)++(p××n)++(m××q)++(m××n)
p ×× q∘n = (p××q)++(p××n)
p∘m ×× q = (p××q)++ (m××q)
p ×× q = nimius ⍝ not already covered: overflow.
⍝ Intermediate simplification of expanded strings, speeds up multiply:
I∘I∘I∘I∘I = V
p∘I∘I∘I∘I∘I = p∘V
V∘V = X
p∘V∘V = p∘X
X∘X∘X∘X∘X = L
p∘X∘X∘X∘X∘X = p∘L
L∘L = C
p∘L∘L = p∘C
C∘C∘C∘C∘C = D
p∘C∘C∘C∘C∘C = p∘D
D∘D = M
p∘D∘D = p∘M
⍝ Div ⍝ Integer divide.
p ÷ q = /(div(qr(\p; \q))) ⍝ div expanded strings.
div() ⋄ div(q; r) = q ⍝ extract quotient
⍝ Rem ⍝ Integer remainder.
p % q = /(rem(qr(\p; \q))) ⍝ rem expanded strings.
rem() ⋄ rem(q; r) = r ⍝ extract remainder
⍝ Auxiliary functions for division:
← ;() ⍝ tuple item separation.
qr() ⋄ qr(p; q) = dv(p; (sh(p; q; ⊥)); nulla) ⍝ quotient and remainder.
⍝ Long division:
dv() dv'() dv"() ⍝ division.
dv p; ⊥; r = nulla; p ⍝ dividend too small: done.
dv p; (q; s); r = dv' r; s; (sb p; q; nulla)
dv' r; s; (p; q) = dv" q; s; (p++(10 r))
dv" r; ⊥; q = q; r ⍝ finished.
dv" p; q; r = dv p; q; r
sb() sb'() ⍝ repeated subtraction.
sb p; q; r = sb' p; q; r; (p?q) ⍝ dividend ? subtrahend:
sb' p; q; r; lt = r; p ⍝ p<q:
sb' p; q; r; s = sb p--q; q; r∘I ⍝ p≥q:
sh() sh'() ⍝ divisor "shift".
sh p; q; r = sh' p; q; r; (p?q)
sh' p; q; r; lt = r
sh' p; q; r; s = sh p; (10 q); (q; r)
⍝ Tenfold (note that "10" is a function).
10() ⍝ tenfold.
10 I = X
10 V = L
10 X = C
10 L = D
10 C = M
10 D = nimius ⍝ too big
10 M = nimius ⍝ too big
10 j = j ⍝ ten nothings are still nothing, etc.
10(p∘n) = (10 p)∘(10 n)
⍝ Compare
← ?() ??() ⍝ compare expanded strings.
p ? q = (⌽p)??(⌽q) ⍝ ⌽: compare more significant values first.
m ?? m = eq
I ?? n = lt
m ?? I = gt
V ?? n = lt
m ?? V = gt
X ?? n = lt
m ?? X = gt
L ?? n = lt
m ?? L = gt
C ?? n = lt
m ?? C = gt
D ?? n = lt
m ?? D = gt
M ?? n = lt
m ?? M = gt
p ?? nimius = lt ⍝ compare with "too big"
nimius ?? q = gt
p ?? absurdus = gt ⍝ compare with "too small"
absurdus ?? q = lt
p ?? nulla = gt ⍝ compare with "nothing"
nulla ?? q = lt
m∘p ?? n = (m??n)∘gt
m ?? n∘q = (m??n)∘lt
m∘p ?? n∘q = (m??n)∘(p??q)
eq∘q = q
lt∘q = lt
gt∘q = gt
⍝ Reverse expanded string binding: ((a∘b)∘c)∘d → a∘(b∘(c∘d))
⌽()
⌽j = j
⌽(p∘q) = ⌽⌽(p;q)
⌽⌽()
⌽⌽(j;r) = j∘r
⌽⌽(p∘q;r) = ⌽⌽(p;q∘r)
⍝ Expand (remove subtractive prefixes). See →notes.roman←
\j = j
\I.V = I∘I∘I∘I
\I.X = V∘I∘I∘I∘I
\X.L = X∘X∘X∘X
\X.C = L∘X∘X∘X∘X
\C.D = C∘C∘C∘C
\C.M = D∘C∘C∘C∘C
\p.I.V = \p∘I∘I∘I∘I
\p.I.X = \p∘V∘I∘I∘I∘I
\p.X.L = \p∘X∘X∘X∘X
\p.X.C = \p∘L∘X∘X∘X∘X
\p.C.D = \p∘C∘C∘C∘C
\p.C.M = \p∘D∘C∘C∘C∘C
\p.n = \p∘n
⍝ Compress: replace '∘' with '.' to enable renormalisation.
/j = j
/(p∘n) = (/p).n
⍝ Normalise (per norma)
I.I.I.I = I.V
p.I.I.I.I = p.I.V
I.V.I = V
p.I.V.I = p.V
V.I.I.I.I = I.X
p.V.I.I.I.I = p.I.X
I.X.I = X
p.I.X.I = p.X
V.I.V = I.X
p.V.I.V = p.I.X
X.X.X.X = X.L
p.X.X.X.X = p.X.L
X.L.X = L
p.X.L.X = p.L
X.X.X.X.I.X = X.L.I.X
p.X.X.X.X.I.X = p.X.L.I.X
L.X.L = X.C
p.L.X.L = p.X.C
X.C.X = C
p.X.C.X = p.C
C.C.C.C = C.D
p.C.C.C.C = p.C.D
C.D.C = D
p.C.D.C = p.D
D.C.C.C.C = C.M
p.D.C.C.C.C = p.C.M
D.C.D = C.M
p.D.C.D = p.C.M
C.M.C = M
p.C.M.C = p.M
V.V = X
p.V.V = p.X
L.L = C
p.L.L = p.C
D.D = M
p.D.D = p.M
M.M.M.M = nimius ⍝ overflow (too big)
p.i = p ⍝ special values.
i.q = q
p.k = k
k.q = k
⍝ Roman from Arabic 1 ·· 3,999
⍴⍴() ⍝ Auxiliary function
⍴ p = ⍴⍴(p∘I) ⍝ start with I units
⍴⍴(0∘I) = nulla ⍝⍝⍝⍝
⍴⍴(1∘I) = I ⍝
⍴⍴(2∘I) = I.I ⍝
⍴⍴(3∘I) = I.I.I ⍝
⍴⍴(4∘I) = I.V ⍝
⍴⍴(5∘I) = V ⍝
⍴⍴(6∘I) = V.I ⍝
⍴⍴(7∘I) = V.I.I ⍝
⍴⍴(8∘I) = V.I.I.I ⍝
⍴⍴(9∘I) = I.X ⍝
⍝ 1 ·· 9
⍴⍴(p.0∘I) = ⍴⍴(p∘X) ⍝
⍴⍴(p.1∘I) = (⍴⍴(p∘X)).I ⍝
⍴⍴(p.2∘I) = (⍴⍴(p∘X)).I.I ⍝
⍴⍴(p.3∘I) = (⍴⍴(p∘X)).I.I.I ⍝
⍴⍴(p.4∘I) = (⍴⍴(p∘X)).I.V ⍝
⍴⍴(p.5∘I) = (⍴⍴(p∘X)).V ⍝
⍴⍴(p.6∘I) = (⍴⍴(p∘X)).V.I ⍝
⍴⍴(p.7∘I) = (⍴⍴(p∘X)).V.I.I ⍝
⍴⍴(p.8∘I) = (⍴⍴(p∘X)).V.I.I.I ⍝
⍴⍴(p.9∘I) = (⍴⍴(p∘X)).I.X ⍝⍝⍝⍝
⍴⍴(1∘X) = X ⍝⍝⍝⍝
⍴⍴(2∘X) = X.X ⍝
⍴⍴(3∘X) = X.X.X ⍝
⍴⍴(4∘X) = X.L ⍝
⍴⍴(5∘X) = L ⍝
⍴⍴(6∘X) = L.X ⍝
⍴⍴(7∘X) = L.X.X ⍝
⍴⍴(8∘X) = L.X.X.X ⍝
⍴⍴(9∘X) = X.C ⍝
⍝ 1.0 ·· 9.0
⍴⍴(p.0∘X) = ⍴⍴(p∘C) ⍝
⍴⍴(p.1∘X) = (⍴⍴(p∘C)).X ⍝
⍴⍴(p.2∘X) = (⍴⍴(p∘C)).X.X ⍝
⍴⍴(p.3∘X) = (⍴⍴(p∘C)).X.X.X ⍝
⍴⍴(p.4∘X) = (⍴⍴(p∘C)).X.L ⍝
⍴⍴(p.5∘X) = (⍴⍴(p∘C)).L ⍝
⍴⍴(p.6∘X) = (⍴⍴(p∘C)).L.X ⍝
⍴⍴(p.7∘X) = (⍴⍴(p∘C)).L.X.X ⍝
⍴⍴(p.8∘X) = (⍴⍴(p∘C)).L.X.X.X ⍝
⍴⍴(p.9∘X) = (⍴⍴(p∘C)).X.C ⍝⍝⍝⍝
⍴⍴(1∘C) = C ⍝⍝⍝⍝
⍴⍴(2∘C) = C.C ⍝
⍴⍴(3∘C) = C.C.C ⍝
⍴⍴(4∘C) = C.D ⍝
⍴⍴(5∘C) = D ⍝
⍴⍴(6∘C) = D.C ⍝
⍴⍴(7∘C) = D.C.C ⍝
⍴⍴(8∘C) = D.C.C.C ⍝
⍴⍴(9∘C) = C.M ⍝
⍝ 1.0.0 ·· 9.0.0
⍴⍴(p.0∘C) = ⍴⍴(p∘M) ⍝
⍴⍴(p.1∘C) = (⍴⍴(p∘M)).C ⍝
⍴⍴(p.2∘C) = (⍴⍴(p∘M)).C.C ⍝
⍴⍴(p.3∘C) = (⍴⍴(p∘M)).C.C.C ⍝
⍴⍴(p.4∘C) = (⍴⍴(p∘M)).C.D ⍝
⍴⍴(p.5∘C) = (⍴⍴(p∘M)).D ⍝
⍴⍴(p.6∘C) = (⍴⍴(p∘M)).D.C ⍝
⍴⍴(p.7∘C) = (⍴⍴(p∘M)).D.C.C ⍝
⍴⍴(p.8∘C) = (⍴⍴(p∘M)).D.C.C.C ⍝
⍴⍴(p.9∘C) = (⍴⍴(p∘M)).C.M ⍝⍝⍝⍝
⍴⍴(1∘M) = M ⍝⍝⍝⍝
⍴⍴(2∘M) = M.M ⍝ 1.0.0.0 ·· 3.0.0.0
⍴⍴(3∘M) = M.M.M ⍝⍝⍝⍝
⍴⍴(p) = nimius ⍝⍝⍝⍝ otherwise: too big
⍝ Arabic from Roman
⍺⍺() ⍝ Auxiliary function.
← <+>() ⍝ add multi-digit Arabic numbers.
a b :: 0 1 2 3 4 5 6 7 8 9 ⍝ Arabic digits
⍺ r = ⍺⍺(\r)
⍺⍺ i = 0
⍺⍺ I = 1
⍺⍺ V = 5
⍺⍺ X = 1.0
⍺⍺ L = 5.0
⍺⍺ C = 1.0.0
⍺⍺ D = 5.0.0
⍺⍺ M = 1.0.0.0
⍺⍺ nulla = 0
⍺⍺ nimius = too_big
⍺⍺ absurdus = negative
⍺⍺(p∘m) = ⍺⍺p <+> ⍺⍺m
a <+> 0 = a
0 <+> b = b
1 <+> 1 = 2
2 <+> 1 = 3
3 <+> 1 = 4
4 <+> 1 = 5
5 <+> 1 = 6
6 <+> 1 = 7
7 <+> 1 = 8
8 <+> 1 = 9
p.a <+> b = p.(a<+>b)
p.a <+> q.b = (p<+>q).(a<+>b)
⍝ Equivalence functions
← =() ≡() ⍝ reduction equivalence/trace
⍝ Test Cases
⍝
⍝ I.I.I.I -> I.V ⍝ normalisation
⍝ I.I.I.I.I -> V
⍝ I.I.I.I.I.I -> V.I
⍝
⍝ I+I+I+I+I+I -> V.I ⍝ addition
⍝ I.V + I -> V
⍝ V.I.I + V.I.I -> X.I.V
⍝ I.X + I.X -> X.V.I.I.I
⍝ X.L.I.X + X.L.I.X -> X.C.V.I.I.I
⍝ M+M+M+M -> nimius
⍝
⍝ X.X - I -> X.I.X ⍝ subtraction.
⍝ V.I - V -> I
⍝ X-I.I.I.I.I.I.I.I.I -> I
⍝ X.X - I.I -> X.V.I.I.I
⍝ X.I.V - V.I -> V.I.I.I
⍝ C.I - V -> X.C.V.I
⍝ M.M - I -> M.C.M.X.C.I.X
⍝ X-V-V -> nulla
⍝ X-V-V-V -> absurdus
⍝
⍝ X.I.V × X.I.V -> C.X.C.V.I ⍝ multiplication
⍝ X×X×X -> M
⍝ X×X×X×X -> nimius
⍝ I.I × nulla -> nulla
⍝
⍝ V ÷ I -> V ⍝ division
⍝ C ÷ X -> X
⍝ X.I ÷ I.I -> V
⍝ C.X.L.V ÷ V.I -> X.X.I.V
⍝ V ÷ X -> nulla
⍝ X.I.I ÷ V -> I.I
⍝
⍝ C.X.L.V % V.I -> I ⍝ remainder
⍝ X % V -> nulla
⍝ V % X -> V
⍝ X.I.I % V -> I.I
⍝
⍝ ⍴ 1.9.9.9 -> M.C.M.X.C.I.X ⍝ Roman from Arabic
⍝ ⍴ 3.9.9.9 -> M.M.M.C.M.X.C.I.X
⍝ ⍴ 4.0.0.0 -> nimius ⍝ (number too big)
⍝
⍝ ⍺ M.C.M.X.C.I.X -> 1.9.9.9 ⍝ Arabic from Roman
⍝ ⍺ M.M.M.C.M.X.C.I.X -> 3.9.9.9
⍝
⍝ ⍺⍴ 4.9 -> 4.9 ⍝ round trip.
⍝ ⍴⍺ C.M.X.C.I.X -> C.M.X.C.I.X ⍝ .. ..
⍝ ⍴⍺ C.D.X.L.I.V -> C.D.X.L.I.V ⍝ .. ..
⍝
⍝ M + I.X × C.X.I -> M.C.M.X.C.I.X ⍝ misc
⍝
⍝ Back to: Contents