math::roman(3)

NAME

Math::Roman - Arbitrary sized Roman numbers and conversion
from and to Arabic.

SYNOPSIS

use Math::Roman qw(roman);
$a = new Math::Roman 'MCMLXXIII';  # 1973
$b = roman('MCMLXI');              # 1961
print $a - $b,"0;                # prints 'XII'
$d = Math::Roman->bzero();         # ''
$d++;                              # 'I'
$d += 1998;                        # 'MCMXCIX'
$d -= 'MCM';                       # 'XCIX'
print      "$d0;                          #     string
"MCMIC"
print   $d->as_number(),"0;          #    Math::BigInt
"+1999"

REQUIRES

perl5.005, Exporter, Math::BigInt

EXPORTS

Exports nothing on default, but can export "as_number()",
"roman()", and "error()".

DESCRIPTION

Well, it seems I have been infected by the Perli
gata-Virus, too. ;o)

This module lets you calculate with Roman numbers, as if
they were big integers. The numbers can have arbitrary
length and all the usual functions from Math::BigInt are
available.

INPUT

The Roman single digits are as follows:
I 1
V 5
X 10
L 50
C 100
D 500
M 1000
The following (quite modern) rules are in effect:

Each of I, X and C can be repeated up to 3 times, V, L
and D only once. Technically, M could be used up to four
times, but this module imposes no limit on this to allow
arbitrarily big numbers.
A Roman number consists of tokens, each token is either a digit from IVXLCDM or consist of two digits, whereas the
first digit is smaller than the second one. In the latter
case the first digit is subtracted from the second (e.g.
IV means 4, not 6).
The smaller number must be a power of ten (I, X or C) and
precede a number no larger than 10 times its own value.
The smaller number itself can be preceded only by a num
ber at least 10 times greater (e.g. LXC is invalid) and
it must also be larger than any numeral that follows the
one from which it is being subtracted (e.g. CMD is
invalid).
Each token must be smaller than the token before (e.g.
IIV is invalid, since I is smaller than IV).
The input will be checked and the result will be a 'NaN'
if the check fails. You can get the cause with
"Math::Roman::error()" until you try to create the next
Roman number.
The default list of valid tokens a Roman number can con
sist of is thus:

III 3
XXX 30
CCC 300
II 2
XX 20
CC 200
IV 4
IX 9
XL 40
XC 90
CD 400
CM 900
I 1
V 5
X 10
L 50
C 100
D 500
M 1000
The default list of invalid tokens is as follows:

IIII XXXX CCCC
DD LL VV
C[MD][CDM] X[LC][XLCDM] I[VX][IVXLCDM]
Thanx must go to http://netdirect.net/~charta/Roman_numer
als.html for clarifications.
OUTPUT
The output will always be of the shortest possible form,
and the tokens will be arranged in a decreasing order.

BENDING THE RULES

You can use "Math::Roman::tokens()" to get an array with
all the defined tokens and their value. Tokens with a
value of -1 are invalid, all others are valid. The format
is token0, value0, token1, value1...

You can create your own set and store it with
"Math::Roman::tokens()". The routine expects an array of
the form token, value, token, value... etc. Each token
can be a simple string or regular expresion. Values of -1
indicate invalid tokens.

Here is an example that removes the subtraction (only
addition is valid) as well as most of the other rules. It
then parses 'XIIII' to be 14, then redefine the token set
completely and parses 'AAB' to be 25:
use Math::Roman;
Math::Roman::tokens( qw(I 1 V 5 X 10 L 50 C
100 D 500 M 1000));
$r = Math::Roman::roman('XIIII');
print "'$r' is ",$r->as_number(),"0;
$r = Math::Roman::roman('XV');
print "'$r' is ",$r->as_number(),"0;
Math::Roman::tokens ( qw(A 10 B 5) );
$r = Math::Roman::roman('AAB');
print "'$r' is ",$r->as_number(),"0;
Another idea is to implement the dash over symbols, this
indicates multiplying by 1000. Since it is hard to do this
in ASCII, lower-case letters could be used like in the
following:

use Math::Roman;
# will wrongly ommit the 'M's, but so much 'M's
would not fit
# on your screen anyway
print 'old: ',new Math::Roman
('+12345678901234567890'),"0;
@a = Math::Roman::tokens();
push @a, qw ( v 5000 x 10000 l 50000 c 100000
d 500000
m 1000000 );
Math::Roman::tokens(@a);
print 'new: ',new Math::Roman
('+12345678901234567890'),"0;

USEFULL METHODS

nneeww(())
new();
Create a new Math::Roman object. Argument is a Roman num
ber as string, like 'MCMLXXIII' (1973) of the form
/^[IVXLCDM]*$/ (see above for further rules) or a string
number as used by Math::BigInt.
rroommaann(())

roman();
Just like new, but you can import it to write shorter
code.
eerrrroorr(())

Math::Roman::error();
Return error of last number creation when result was NaN.
bbssttrr(())

$roman->bstr();
Return a string representing the internal value as a Roman
number according to the aforementioned rules. A zero will
be represented by ''. The output will only consist of
valid tokens, and not contain a sign. Use "as_number()"
if you need the sign.
This function always generates the shortest possible form,
e.g. it will generate XC and not LXL.
aass__nnuummbbeerr(())

$roman->as_number();
Return a string representing the internal value as a nor
malized arabic number, including sign.

DETAILS

Uses internally Math::BigInt to do the math, all with
overloaded operators.

Roman has neither negative numbers nor zero, but this mod
ule handles these, too. You will get only the absolute
value as Roman number, but can look at the sign with
"sign()" or use "as_number()".

EXAMPLES

use Math::Roman qw(roman);

print Math::Roman->new('MCMLXXII')->as_number(),"0;
print Math::Roman->new('LXXXI')->as_number(),"0;
print roman('MDCCCLXXXVIII')->as_number(),"0;

$a = roman('1311');
print "$a is ",$a->as_number(),"0;

$a = roman('MCMLXXII');
print " is now $a (",$a->as_number(),")0;
$a++; $a += 'MCMXII'; $a = $a * 'X' - 'I';
print " is now $a (",$a->as_number(),")0;

LIMITS

Internal Number Length
For the actual math, the same limits as in Math::BigInt
apply.
Output length
The output in Roman is limited to 65536 times the biggest
symbol. With the default set this is 'M', so the biggest
Roman number you can print is 65536000 - and it will give
you 64 KBytes M's in a row. This could be fixed, but who
really needs it? ;)
Number Rules
The rule "Each token must be greater than the token
before" is hard-coded in and can not be overcome. So
'IIX' will be invalid for subtraction-less numbers unless
you define an 'IIX' token with a value of 12.

BUGS

Ambiguous tokens
Even with the strict rules there are doubtfull cases
like:

LXL == 50+40 == 90 == XC
I can not see how LXL violates any of the aforementioned
rules. The output will always favour the shorter form,
but you can construct valid numbers from the longer
input.
Importing functions
You can not import ordinary math functions like "badd()"
and write things like:

use Math::Roman qw(badd); # will
fail
$a = badd('MCM','M'); # does
not work
$a = Math::Roman::badd('MCM','M'); # neither
It is be possible to make this work, but this takes quite
a lot of Copy&Paste code, and some small overhead price
for every calculation. I think this is really not
needed, since you can always use:

use Math::Roman;
$a = new Math::Roman 'MCM'; $a += 'M'; # neat
isn't it?
$a = Math::Roman->badd('MCM','M'); # or this
'0'-'9' as tokens
0-9 in the token set produce wrong results in new() if
the given argument consists only of 0-9. That is because
first a BigInt is tried to be constructed, and in this
case, would succeed.

LICENSE

This program is free software; you may redistribute it
and/or modify it under the same terms as Perl itself.

AUTHOR

If you use this module in one of your projects, then
please email me. I want to hear about how my code helps
you ;)

Copyright (C) MCMXCIX-MM by Tels <http://bloodgate.com/>
Copyright © 2010-2025 Platon Technologies, s.r.o.           Index | Man stránky | tLDP | Dokumenty | Utilitky | O projekte
Design by styleshout