home *** CD-ROM | disk | FTP | other *** search
- /* arab2rom.c
-
- David S McMeans Not copyrighted April 1993
- mcmeans@dtedi.hq.aflc.af.mil
-
- Arabic2Roman()
- Converts an Arabic integer to its Roman equivalent.
-
- Call
-
- char *Arabic2Roman( num, buf )
- unsigned long int num; integer to convert
- char *buf; buffer in which conversion is returned
-
- Returns
-
- NULL if num is out of range 0 to 3,999,999.
-
- POINTER otherwise
-
- Description
-
- The Romans had no concept of fractions, so all their numbers were integers.
- At the time their system was created, one thousand was as large a number as
- could be conceived and thus was given the letter M for magna (large). A
- later modification extended the system a thousand fold. Any numeral with a
- bar over it was defined as one thousand times its normal value. Since it is
- not possible to write a character with an over-bar in ASCII, these numerals
- are written with an underscore to their right ( M_ = 1000 * 1000 ).
-
- I 1
- V 5 V_ 5,000
- X 10 X_ 10,000
- L 50 L_ 50,000
- C 100 C_ 100,000
- D 500 D_ 500,000
- M 1000 M_ 1,000,000
-
- When a number has multiple forms, it's canonical form is the shorter. Nine
- is written IX, not VIIII, and ninety is XC, not LXXXX. But, a numeral is
- not allowed to modify another that is more than one maginitude greater.
- The correct representation of 1990 is not MXM (1000 + 1000-10). Rather, it
- is MCMXC (1000 + 1000-100 + 100-10). When writing 1990, you first write
- the representation for 1000, then for 900, and then for 90. You do not write
- down the numerals for 1000 and then for 990. The technique is to integrally
- divide the number by its greatest magnitude and write down the Roman
- representation for each result. For 1989, the greatest magnitude is 1000.
- You would write down M. Divide by 1000, and the result is 989. Here the
- largest magnitude is 900. Write down CM (1000-100). Strip off the 900, and
- get 89. Now the greatest magnitude is 80. Write down LXXX. This leaves 9
- which would be written as IX.
-
- This system follows a peculiar pattern of addtion and subraction to generate
- the values one through 10. Smaller numerals to the left of a larger are
- subracted from the larger, and smaller numerals placed to the right are added.
-
- 1 I 11 XI 40 XL
- 2 II 12 XII
- 3 III 13 XIII 50 L
- 4 IV 14 IVX
- 5 V 15 XV 90 XC
- 6 VI 16 XVI
- 7 VII 17 XVII 100 C
- 8 VIII 18 XVIII
- 9 IX 19 XIX
- 10 X 20 XX
-
- Note that 8, VIII, could be written more succinctly IIX (10-2). I expect,
- only one numeral may be placed in a subtraction position.
-
- The following constant strings are redefinable by the user. This allows one
- to substitute different characters for over-bar numerals.
-
- Roman_1 = "i"; Roman_5000 = "v_";
- Roman_5 = "v"; Roman_10000 = "x_";
- Roman_10 = "x"; Roman_50000 = "l_";
- Roman_50 = "l"; Roman_100000 = "c_";
- Roman_100 = "c"; Roman_500000 = "d_";
- Roman_500 = "d"; Roman_1000000 = "m_";
- Roman_1000 = "m";
-
- To represent numbers four million and greater, a numeral for five million is
- needed. Since no numerals exist above one million (though they could easily
- be fabricated), Arabic2Roman() converts integers only in the range 0 to
- 3,999,999.
-
- Notes
-
- This was compiled from a discussion in comp.lang.pascal around March 1993.
- Acknowledgements go to John J Cupak Jr, CPP (cupak@rapnet.sanders.lockheed.com),
- Paul Robinson (tdarcos@access.digex.com), and
- David Conrad (dave@tygra.michigan.com) for their informative articles,
- Prof Timo Salmi (ts@uwasa.fi) for steering me in the direction of the
- discussion, and to Arlin B Collins (bcollins@utdallas.edu) for sending me his
- collection of the articles from the discussion.
-
- Arabic2Roman() is a modified version of the Turbo Pascal function Roman in
- tools.pas which is in garbo.uwasa.fi:/pc/turbopas/drcpas10.zip
-
- */
-
-
- #include "tailor.h"
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
-
- #define ulong unsigned long int
-
- /* The following constants determine the representation of each Roman
- numeral, and may be redefined by the user
- */
-
- char *Roman_1 = "i";
- char *Roman_5 = "v";
- char *Roman_10 = "x";
- char *Roman_50 = "l";
- char *Roman_100 = "c";
- char *Roman_500 = "d";
- char *Roman_1000 = "m";
- char *Roman_5000 = "v_";
- char *Roman_10000 = "x_";
- char *Roman_50000 = "l_";
- char *Roman_100000 = "c_";
- char *Roman_500000 = "d_";
- char *Roman_1000000 = "m_";
-
- /*
- * PUBLIC DECLARATIONS
- */
-
- extern char *Arabic2Roman OF(( ulong, char * ));
-
- /*
- * PRIVATE DECLARATIONS
- */
-
- static void roman_digit OF(( char *, char *, char *, ulong, char * ));
-
- char *Arabic2Roman( num, buf )
- ulong num;
- char *buf;
- {
- strcpy( buf, "" );
-
- if (num > 3999999)
- return NULL;
-
- roman_digit( Roman_1000000, " ", " ", num/1000000, buf );
- num %= 1000000;
- roman_digit( Roman_100000, Roman_500000, Roman_1000000, num/100000, buf );
- num %= 100000;
- roman_digit( Roman_10000, Roman_50000, Roman_100000, num/10000, buf );
- num %= 10000;
- roman_digit( Roman_1000, Roman_5000, Roman_10000, num/1000, buf );
- num %= 1000;
- roman_digit( Roman_100, Roman_500, Roman_1000, num/100, buf );
- num %= 100;
- roman_digit( Roman_10, Roman_50, Roman_100, num/10, buf );
- num %= 10;
- roman_digit( Roman_1, Roman_5, Roman_10, num, buf );
-
- return buf;
- }
-
- static void roman_digit( one, five, ten, n, buf )
- char *one, *five, *ten;
- ulong n;
- char *buf;
- {
- int i;
-
- switch( n )
- {
- case 1: case 2: case 3:
- for (i=0; i < n; i++)
- strcat( buf, one );
- break;
- case 4:
- strcat( buf, one );
- strcat( buf, five );
- break;
- case 5: case 6: case 7: case 8:
- strcat( buf, five );
- for (i=0; i < n-5; i++)
- strcat( buf, one );
- break;
- case 9:
- strcat( buf, one );
- strcat( buf, ten );
- break;
- }
- }
-
- /* end .c */
-