Advertisement
B1KMusic

roman numeral printer

Oct 1st, 2015
290
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 2.98 KB | None | 0 0
  1. /* Int to roman numeral printer by Braden Best (2015) */
  2.  
  3. #include <stdio.h>
  4.  
  5. typedef enum{
  6.     I  = 1,
  7.     IV = 4,
  8.     V  = 5,
  9.     IX = 9,
  10.     X  = 10,
  11.     XL = 40,
  12.     L  = 50,
  13.     XC = 90,
  14.     C  = 100,
  15.     CD = 400,
  16.     D  = 500,
  17.     CM = 900,
  18.     M  = 1000,
  19. } Roman_Numeral;
  20.  
  21. const Roman_Numeral numerals[] = {M, CM, D, CD, C, XC, L, XL, X, IX, V, IV, I};
  22.  
  23. const char *roman_str(Roman_Numeral r){
  24.     switch(r){
  25.         case I:  return "I";
  26.         case IV: return "IV";
  27.         case V:  return "V";
  28.         case IX: return "IX";
  29.         case X:  return "X";
  30.         case XL: return "XL";
  31.         case L:  return "L";
  32.         case XC: return "XC";
  33.         case C:  return "C";
  34.         case CD: return "CD";
  35.         case D:  return "D";
  36.         case CM: return "CM";
  37.         case M:  return "M";
  38.     }
  39. }
  40.  
  41. void print_roman(int n){
  42.     int i = 0;
  43.     while(n){
  44.         while(n >= numerals[i]){
  45.             n -= numerals[i];
  46.             fputs(roman_str(numerals[i]), stdout);
  47.         }
  48.         i++;
  49.     }
  50. }
  51.  
  52. int main(int argc, char **argv){
  53.     int n;
  54.     for (n = 1; n <= 2000; n++){
  55.         printf("%i = ", n);
  56.         print_roman(n);
  57.         printf("\n");
  58.     }
  59.     return 0;
  60. }
  61.  
  62. /* Prints roman numerals for n {1..2000} */
  63.  
  64. /* How it works:
  65.  *
  66.  * It's a simple matter of reduction. I start from the largest unit, M, and subtract 1,000 until N < 1000, then continue with progressively smaller units.
  67.  *
  68.  * You'd think IV, IX, etc would be tough to sort out, but when you think of them as a single unit, rather than two separate units, it becomes clear that IX, for example, explicitly means 9, and nothing else. 1999 is MCMXCIX, or M(1000) CM(900) XC(90) IX(9)
  69.  * Roman numerals are actually very simple.
  70.  *
  71.  * However, with 13 possible units, this means either an absurdly ugly if-else chain or 13 while loops. Do not lower yourself to doing this. There is always a better way.
  72.  *
  73.  * So I defined an enumerated type, a lookup function to complement it, and a reducer function to do the job of what would be 13 while loops.
  74.  *
  75.  * The code is now far more readable, with a clear intent, and no need to be riddled with comments explaining every line, as every line is more or less self-explanatory depending on one's skill level.
  76.  *
  77.  * Remember, you will read your code far more than you will write it, so it's essential to know how to make it easily readable. If you can only remember one 'golden rule' for the rest of your life, make it this one.
  78.  *
  79.  * And I urge you to study the above code to understand it.
  80.  */
  81.  
  82. /*
  83.  
  84. Updates:
  85.  
  86. Removed reducer(), combined with print_roman()
  87.  
  88. Moved Roman_Numeral array to global namespace as a constant to save a little bit on performance. Instead of re-creating the array every time the function is loaded, the array is created once.
  89.  
  90. print_roman() now runs until n == 0, rather than until it reaches the end of the array.
  91.  
  92. Removed leftover <stdlib.h> from the char * version of print_roman(), which used malloc()
  93.  
  94. */
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement