Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adjust subtractives to match standard form #2

Merged
merged 3 commits into from
Jun 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,35 @@ Future enhancements will include expansions to printf/sprintf with a custom form

While it handles both additive and subtractive Roman numerals, it doesn't check that they're properly formatted. For instance 'IC' should be a compile-time error but instead it'll generate 101 as if nothing of consequence happened.

REFERENCE
=========

According to [Wikipedia](https://en.wikipedia.org/wiki/Roman_numerals), the standard form is:

+---+-----------+----------+------+-------+
| | Thousands | Hundreds | Tens | Units |
+---+-----------+----------+------+-------+
| 1 | M | C | X | I |
+---+-----------+----------+------+-------+
| 2 | MM | CC | XX | II |
+---+-----------+----------+------+-------+
| 3 | MMM | CCC | XXX | III |
+---+-----------+----------+------+-------+
| 4 | | CD | XL | IV |
+---+-----------+----------+------+-------+
| 5 | | D | L | V |
+---+-----------+----------+------+-------+
| 6 | | DC | LX | VI |
+---+-----------+----------+------+-------+
| 7 | | DCC | LXX | VII |
+---+-----------+----------+------+-------+
| 8 | | DCCC | LXXX | VIII |
+---+-----------+----------+------+-------+
| 9 | | CM | XC | IX |
+---+-----------+----------+------+-------+

The numerals for 4 (IV) and 9 (IX) are written using subtractive notation,where the smaller symbol (I) is subtracted from the larger one (V, or X), thus avoiding the clumsier IIII and VIIII. Subtractive notation is also used for 40 (XL), 90 (XC), 400 (CD) and 900 (CM). These are the only subtractive forms in standard use.

AUTHOR
======

Expand Down
37 changes: 18 additions & 19 deletions lib/Slang/Roman.rakumod
Original file line number Diff line number Diff line change
Expand Up @@ -64,25 +64,24 @@ my sub to-roman(Int:D $val) is export {
my sub to-number(Str:D $value) is export {

# Find subtractives and convert them to additives
#
# IV => IIII ( 5 - 1 == 4 )
# IX => VIIII ( 10 - 1 == 9 )
# XL => XXXX ( 50 - 10 == 40 )
# IL => XXXXVIIII ( 50 - 1 == 49 )
# XC => LXXXX ( 100 - 10 == 90 )
# CD => CCCC ( 500 - 100 == 400 )
# CM => DCCCC ( 1000 - 100 == 900 )

$value.subst(/
(<[ I Ⅰ X Ⅹ C Ⅽ M Ⅿ ↂ ]>)
(<[ V Ⅴ X Ⅹ L Ⅼ C Ⅽ D Ⅾ M Ⅿ ↁ ↂ ↇ ↈ ]>)
/, {
%char-map{$0} < %char-map{$1}
?? to-roman(%char-map{$1} - %char-map{$0})
!! $0 ~ $1
}, :global).comb.map({
%char-map{$_} // die "Unexpected '$_' in Roman numeral"
}).sum

my %subtractives = (
IV => 'IIII', #( 5 - 1 == 4 )
IX => 'VIIII', #( 10 - 1 == 9 )
XL => 'XXXX', #( 50 - 10 == 40 )
XC => 'LXXXX', #( 100 - 10 == 90 )
CD => 'CCCC', #( 500 - 100 == 400 )
CM => 'DCCCC', #( 1000 - 100 == 900 )
);

my Pair $p = (.keys => .values) given %subtractives;

$value
.trans( $p )
.comb.map({
%char-map{$_} // die "Unexpected '$_' in Roman numeral"
})
.sum
}

my role Grammar {
Expand Down
4 changes: 2 additions & 2 deletions t/01-basic.rakutest
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ subtest sub {
is 0rXIV, 14, q{Roman numeral 14 subtractive};
is 0rXIX, 19, q{Roman numeral 19 subtractive};
is 0rXLIV, 44, q{Roman numeral 44 subtractive};
is 0rIC, 99, q{Roman numeral 99 subtractive};
is 0rMIM, 1999, q{Roman numeral 1999 subtractive};
is 0rXC, 90, q{Roman numeral 90 subtractive};
is 0rMCM, 1900, q{Roman numeral 1900 subtractive};
}, 'subtractive';

is 0rMMXVI, 2016, q{Year of module release};
Expand Down
Loading