How do you find a roman numeral equivalent of an integer
Asked Answered
L

4

21

How do you find a roman numeral equivalent of an integer. Is there a java library which provides this capability?

I did find a similar question, but I would prefer an out of the box API abstraction for this issue. Its just painful to handle all possible combinations in your code.

Logroll answered 13/10, 2010 at 8:21 Comment(6)
There are hundreds of code samples for that on the internet. Why do you ask for that in a forum instead of using google?Met
It isn't painful, it is a very good introduction to Test Driven Development.Domain
Code samples, yes. Standard libraries, no. The question is perfectly valid.Clo
If you are just looking for a library, then this has nothing to do with math.Alphanumeric
I guess nobody bothers to create a library because there are so many code samples. Given the choice between adding another dependency and just copy-pasting some code, most people would probably choose the second.Paderewski
My guess is that nobody bothers because ... hardly any real applications need to do roman number conversion. Only homework questions, lame job interview questions and websites whose real purpose is to attract clicks for advertising revenue. (And the latter are probably coded in PHP ...)Consideration
T
13

Here is a link for many languages including Java. Here's an extract of relevance:

public class RN {

    enum Numeral {
        I(1), IV(4), V(5), IX(9), X(10), XL(40), L(50), XC(90), C(100), CD(400), D(500), CM(900), M(1000);
        int weight;

        Numeral(int weight) {
            this.weight = weight;
        }
    };

    public static String roman(long n) {

        if( n <= 0) {
            throw new IllegalArgumentException();
        }

        StringBuilder buf = new StringBuilder();

        final Numeral[] values = Numeral.values();
        for (int i = values.length - 1; i >= 0; i--) {
            while (n >= values[i].weight) {
                buf.append(values[i]);
                n -= values[i].weight;
            }
        }
        return buf.toString();
    }

    public static void test(long n) {
        System.out.println(n + " = " + roman(n));
    }

    public static void main(String[] args) {
        test(1999);
        test(25);
        test(944);
        test(0);
    }

}
Tranquillize answered 13/10, 2010 at 8:26 Comment(3)
God, this is ugly code. Unfortunately it's probably the most efficient solution (+1).Clo
Thats not ugly, was s**t scared, expecting some regex mumbo-jumbo. The problem is with the variable naming!Ecospecies
You can just tell that they only wrote "weigth" because they actually pronounce it "weight'th". I almost don't disapprove.Courtenay
P
9

This is the code I am using, right next to the excel column name converter. Why isnt there an apache library for this stuff?

private static final char[] R = {'ↂ', 'ↁ', 'M', 'D', 'C', 'L', 'X', 'V', 'I'};
// or, as suggested by Andrei Fierbinteanu
// private static final String[] R = {"X\u0305", "V\u0305", "M", "D", "C", "L", "X", "V", "I"};
private static final int MAX = 10000; // value of R[0], must be a power of 10

private static final int[][] DIGITS = {
    {},{0},{0,0},{0,0,0},{0,1},{1},
    {1,0},{1,0,0},{1,0,0,0},{0,2}};

public static String int2roman(int number) {
    if (number < 0 || number >= MAX*4) throw new IllegalArgumentException(
            "int2roman: " + number + " is not between 0 and " + (MAX*4-1));
    if (number == 0) return "N";
    StringBuilder sb = new StringBuilder();
    int i = 0, m = MAX;
    while (number > 0) {
        int[] d = DIGITS[number / m];
        for (int n: d) sb.append(R[i-n]);
        number %= m;
        m /= 10;
        i += 2;
    }
    return sb.toString();
}

Edit:

Now that I look at it again, the loop can be condensed to

    for (int i = 0, m = MAX; m > 0; m /= 10, i += 2) {
        int[] d = DIGITS[(number/m)%10];
        for (int n: d) sb.append(R[i-n]);
    }

making the code even less readable ;-)

Paderewski answered 13/10, 2010 at 9:2 Comment(3)
I like this code (+1), but I'd return null for n < 0 and throw an IllegalArgumentException for too large numbersClo
Yes, that would be more correct. I just pasted it for the algorithm.Paderewski
Also, I think you should probably use "V\u0305" (V with upper bar) for 5000 and "X\u0305" (X with upper bar) for 10000.Bissell
M
3

This my answer:

Use this libreries...

import java.util.LinkedHashMap;
import java.util.Map;

The code

  public static String RomanNumerals(int Int) {
    LinkedHashMap<String, Integer> roman_numerals = new LinkedHashMap<String, Integer>();
    roman_numerals.put("M", 1000);
    roman_numerals.put("CM", 900);
    roman_numerals.put("D", 500);
    roman_numerals.put("CD", 400);
    roman_numerals.put("C", 100);
    roman_numerals.put("XC", 90);
    roman_numerals.put("L", 50);
    roman_numerals.put("XL", 40);
    roman_numerals.put("X", 10);
    roman_numerals.put("IX", 9);
    roman_numerals.put("V", 5);
    roman_numerals.put("IV", 4);
    roman_numerals.put("I", 1);
    String res = "";
    for(Map.Entry<String, Integer> entry : roman_numerals.entrySet()){
      int matches = Int/entry.getValue();
      res += repeat(entry.getKey(), matches);
      Int = Int % entry.getValue();
    }
    return res;
  }
  public static String repeat(String s, int n) {
    if(s == null) {
        return null;
    }
    final StringBuilder sb = new StringBuilder();
    for(int i = 0; i < n; i++) {
        sb.append(s);
    }
    return sb.toString();
  }

Testing the code

  for (int i = 1;i<256;i++) {
    System.out.println("i="+i+" -> "+RomanNumerals(i));
  }

The output:

  i=1 -> I
  i=2 -> II
  i=3 -> III
  i=4 -> IV
  i=5 -> V
  i=6 -> VI
  i=7 -> VII
  i=8 -> VIII
  i=9 -> IX
  i=10 -> X
  i=11 -> XI
  i=12 -> XII
  i=13 -> XIII
  i=14 -> XIV
  i=15 -> XV
  i=16 -> XVI
  i=17 -> XVII
  i=18 -> XVIII
  i=19 -> XIX
  i=20 -> XX
  i=21 -> XXI
  i=22 -> XXII
  i=23 -> XXIII
  i=24 -> XXIV
  i=25 -> XXV
  i=26 -> XXVI
  i=27 -> XXVII
  i=28 -> XXVIII
  i=29 -> XXIX
  i=30 -> XXX
  i=31 -> XXXI
  i=32 -> XXXII
  i=33 -> XXXIII
  i=34 -> XXXIV
  i=35 -> XXXV
  i=36 -> XXXVI
  i=37 -> XXXVII
  i=38 -> XXXVIII
  i=39 -> XXXIX
  i=40 -> XL
  i=41 -> XLI
  i=42 -> XLII
  i=43 -> XLIII
  i=44 -> XLIV
  i=45 -> XLV
  i=46 -> XLVI
  i=47 -> XLVII
  i=48 -> XLVIII
  i=49 -> XLIX
  i=50 -> L
  i=51 -> LI
  i=52 -> LII
  i=53 -> LIII
  i=54 -> LIV
  i=55 -> LV
  i=56 -> LVI
  i=57 -> LVII
  i=58 -> LVIII
  i=59 -> LIX
  i=60 -> LX
  i=61 -> LXI
  i=62 -> LXII
  i=63 -> LXIII
  i=64 -> LXIV
  i=65 -> LXV
  i=66 -> LXVI
  i=67 -> LXVII
  i=68 -> LXVIII
  i=69 -> LXIX
  i=70 -> LXX
  i=71 -> LXXI
  i=72 -> LXXII
  i=73 -> LXXIII
  i=74 -> LXXIV
  i=75 -> LXXV
  i=76 -> LXXVI
  i=77 -> LXXVII
  i=78 -> LXXVIII
  i=79 -> LXXIX
  i=80 -> LXXX
  i=81 -> LXXXI
  i=82 -> LXXXII
  i=83 -> LXXXIII
  i=84 -> LXXXIV
  i=85 -> LXXXV
  i=86 -> LXXXVI
  i=87 -> LXXXVII
  i=88 -> LXXXVIII
  i=89 -> LXXXIX
  i=90 -> XC
  i=91 -> XCI
  i=92 -> XCII
  i=93 -> XCIII
  i=94 -> XCIV
  i=95 -> XCV
  i=96 -> XCVI
  i=97 -> XCVII
  i=98 -> XCVIII
  i=99 -> XCIX
  i=100 -> C
  i=101 -> CI
  i=102 -> CII
  i=103 -> CIII
  i=104 -> CIV
  i=105 -> CV
  i=106 -> CVI
  i=107 -> CVII
  i=108 -> CVIII
  i=109 -> CIX
  i=110 -> CX
  i=111 -> CXI
  i=112 -> CXII
  i=113 -> CXIII
  i=114 -> CXIV
  i=115 -> CXV
  i=116 -> CXVI
  i=117 -> CXVII
  i=118 -> CXVIII
  i=119 -> CXIX
  i=120 -> CXX
  i=121 -> CXXI
  i=122 -> CXXII
  i=123 -> CXXIII
  i=124 -> CXXIV
  i=125 -> CXXV
  i=126 -> CXXVI
  i=127 -> CXXVII
  i=128 -> CXXVIII
  i=129 -> CXXIX
  i=130 -> CXXX
  i=131 -> CXXXI
  i=132 -> CXXXII
  i=133 -> CXXXIII
  i=134 -> CXXXIV
  i=135 -> CXXXV
  i=136 -> CXXXVI
  i=137 -> CXXXVII
  i=138 -> CXXXVIII
  i=139 -> CXXXIX
  i=140 -> CXL
  i=141 -> CXLI
  i=142 -> CXLII
  i=143 -> CXLIII
  i=144 -> CXLIV
  i=145 -> CXLV
  i=146 -> CXLVI
  i=147 -> CXLVII
  i=148 -> CXLVIII
  i=149 -> CXLIX
  i=150 -> CL
  i=151 -> CLI
  i=152 -> CLII
  i=153 -> CLIII
  i=154 -> CLIV
  i=155 -> CLV
  i=156 -> CLVI
  i=157 -> CLVII
  i=158 -> CLVIII
  i=159 -> CLIX
  i=160 -> CLX
  i=161 -> CLXI
  i=162 -> CLXII
  i=163 -> CLXIII
  i=164 -> CLXIV
  i=165 -> CLXV
  i=166 -> CLXVI
  i=167 -> CLXVII
  i=168 -> CLXVIII
  i=169 -> CLXIX
  i=170 -> CLXX
  i=171 -> CLXXI
  i=172 -> CLXXII
  i=173 -> CLXXIII
  i=174 -> CLXXIV
  i=175 -> CLXXV
  i=176 -> CLXXVI
  i=177 -> CLXXVII
  i=178 -> CLXXVIII
  i=179 -> CLXXIX
  i=180 -> CLXXX
  i=181 -> CLXXXI
  i=182 -> CLXXXII
  i=183 -> CLXXXIII
  i=184 -> CLXXXIV
  i=185 -> CLXXXV
  i=186 -> CLXXXVI
  i=187 -> CLXXXVII
  i=188 -> CLXXXVIII
  i=189 -> CLXXXIX
  i=190 -> CXC
  i=191 -> CXCI
  i=192 -> CXCII
  i=193 -> CXCIII
  i=194 -> CXCIV
  i=195 -> CXCV
  i=196 -> CXCVI
  i=197 -> CXCVII
  i=198 -> CXCVIII
  i=199 -> CXCIX
  i=200 -> CC
  i=201 -> CCI
  i=202 -> CCII
  i=203 -> CCIII
  i=204 -> CCIV
  i=205 -> CCV
  i=206 -> CCVI
  i=207 -> CCVII
  i=208 -> CCVIII
  i=209 -> CCIX
  i=210 -> CCX
  i=211 -> CCXI
  i=212 -> CCXII
  i=213 -> CCXIII
  i=214 -> CCXIV
  i=215 -> CCXV
  i=216 -> CCXVI
  i=217 -> CCXVII
  i=218 -> CCXVIII
  i=219 -> CCXIX
  i=220 -> CCXX
  i=221 -> CCXXI
  i=222 -> CCXXII
  i=223 -> CCXXIII
  i=224 -> CCXXIV
  i=225 -> CCXXV
  i=226 -> CCXXVI
  i=227 -> CCXXVII
  i=228 -> CCXXVIII
  i=229 -> CCXXIX
  i=230 -> CCXXX
  i=231 -> CCXXXI
  i=232 -> CCXXXII
  i=233 -> CCXXXIII
  i=234 -> CCXXXIV
  i=235 -> CCXXXV
  i=236 -> CCXXXVI
  i=237 -> CCXXXVII
  i=238 -> CCXXXVIII
  i=239 -> CCXXXIX
  i=240 -> CCXL
  i=241 -> CCXLI
  i=242 -> CCXLII
  i=243 -> CCXLIII
  i=244 -> CCXLIV
  i=245 -> CCXLV
  i=246 -> CCXLVI
  i=247 -> CCXLVII
  i=248 -> CCXLVIII
  i=249 -> CCXLIX
  i=250 -> CCL
  i=251 -> CCLI
  i=252 -> CCLII
  i=253 -> CCLIII
  i=254 -> CCLIV
  i=255 -> CCLV

Best Regards

Montford answered 29/6, 2013 at 4:31 Comment(0)
W
0

My version uses unmodified lookup and is more explicit.

 public String numToRoman(int num) {
    int numLength = (int) (Math.log10(num) + 1);
    int place_value = 10;
    final Map<Integer, char[]> romanModeLookup = new HashMap<>();
    romanModeLookup.putAll(Map.of(10, new char[]{'I', 'V', 'X'}, 100, new char[]{'X', 'L', 'C'},
            1000, new char[]{'C', 'D', 'M'}, 10000, new char[]{'M'}));


    final StringBuilder romanBuilder = new StringBuilder();
    while (numLength > 0) {
        numLength--;
        int current_num_at_place_val = (num % place_value) / (place_value / 10);
        System.out.println(current_num_at_place_val);

        if (place_value < 10000) {
            if (current_num_at_place_val == 9) {
                romanBuilder.append(romanModeLookup.get(place_value)[2]).append(romanModeLookup.get(place_value)[0]);
            } else if (current_num_at_place_val >= 5) {
                int remaining_sticks = current_num_at_place_val - 5;
                while (remaining_sticks > 0) {
                    romanBuilder.append(romanModeLookup.get(place_value)[0]);
                    remaining_sticks--;
                }
                romanBuilder.append(romanModeLookup.get(place_value)[1]);

            } else if (current_num_at_place_val == 4) {
                romanBuilder.append(romanModeLookup.get(place_value)[1]).append(romanModeLookup.get(place_value)[0]);
            } else {
                while (current_num_at_place_val > 0) {
                    romanBuilder.append(romanModeLookup.get(place_value)[0]);
                    current_num_at_place_val--;
                }
            }
        } else if (place_value == 10000) {
            while (current_num_at_place_val > 0) {
                romanBuilder.append(romanModeLookup.get(10000)[0]);
                current_num_at_place_val--;
            }
        } else {
            throw new IllegalArgumentException("Number too big for Romanization");
        }
        place_value *= 10;
    }

    return romanBuilder.reverse().toString();}
Watteau answered 5/12, 2021 at 7:58 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.