Tuesday 17 April 2018

Convert integers into roman equivalents

Roman numbers are originated from Roman numerals. Roman numbers are based on 7 different symbols, each symbol represent one unique integer.

Below table summarizes the roman symbol and the decimal number.
Symbol
Value
I
1
V
5
X
10
L
50
C
100
D
500
M
1000

Subtractive notation
Without subtractive notation, the numbers from 1 to 10 are represented like below.
I, II, III, IIII, V, VI, VII, VIII, VIIII, X.

By using subtractive notation, the numbers from 1 to 10 are represented like below.
I, II, III, IV, V, VI, VII, VIII, IX, X

IV means one less than 5 = 4
IX means one less than 10 = 9

By using subtractive notation, numbers from 10 to 100 are represented like below.
X, XX, XXX, XL, L, LX, LXX, LXXX, XC, C

XL means 10 less than 50 = 40
XC means 10 less than 100 = 90

To solve this problem, first we need to identify unique symbols.

Number
Roman Symbol
1
I
4
IV
5
V
9
IX
10
X
40
XL
50
L
90
XC
100
C
400
CD
500
D
900
CM
1000
M

Now let’s see how can we convert the year 2018 into roman.

Step 1: Find out the floor (greatest value less than or equal to the given value) number of 2018 in the above table. Floor value of 2018 is 1000. The roman symbol corresponds to 1000 is "M", keep it aside.

2018 - 1000 = 1018

Step 2: Find out the floor (greatest value less than or equal to the given value) number of 1018 in the above table. Floor value of 1018 is 1000. The roman symbol corresponds to 1000 is 'M', Append this symbol to the symbol we got in step 1. i.e, "M" + "M" = "MM"

1018 - 1000 = 18

Step 3: Find out the floor (greatest value less than or equal to the given value) number of 18 in the above table. Floor value of 18 is 10. The roman symbol corresponds to 10 is 'X', Append this symbol to the symbol we got in step 2. i.e, "MM" + "X" = "MMX"

18 - 10 = 8

Step 4: Find out the floor (greatest value less than or equal to the given value) number of 8 in the above table. Floor value of 8 is 5. The roman symbol corresponds to 5 is 'V', Append this symbol to the symbol we got in step 3. i.e, "MMX" + "V" = "MMXV"

8 - 5 = 3

Step 5: Find out the floor (greatest value less than or equal to the given value) number of 3 in the above table. Floor value of 3 is 1. The roman symbol corresponds to 1 is 'I', Append this symbol to the symbol we got in step 4. i.e, "MMXV" + "I" = "MMXVI"

3 - 1 = 2

Step 6: Find out the floor (greatest value less than or equal to the given value) number of 2 in the above table. Floor value of 2 is 1. The roman symbol corresponds to 1 is 'I', Append this symbol to the symbol we got in step 5. i.e, "MMXVI" + "I" = "MMXVII"

2 - 1 = 1

Step 7: Find out the floor (greatest value less than or equal to the given value) number of 1 in the above table. Floor value of 1 is 1. The roman symbol corresponds to 1 is 'I', Append this symbol to the symbol we got in step 6. i.e, "MMXVII" + "I" = "MMXVIII"

1 - 1 = 0

That’s it, once you reach to 0, the result is "MMXVIII"

RomanGenerator.java
package com.sample.util;

import java.util.*;

public class RomanGenerator {

 private static TreeMap<Integer, String> intToRomanMap = new TreeMap<>();

 static {
  loadMap();
 }

 private static void loadMap() {
  intToRomanMap.put(1, "I");
  intToRomanMap.put(4, "IV");
  intToRomanMap.put(5, "V");
  intToRomanMap.put(9, "IX");
  intToRomanMap.put(10, "X");
  intToRomanMap.put(40, "XL");
  intToRomanMap.put(50, "L");
  intToRomanMap.put(90, "XL");
  intToRomanMap.put(100, "C");
  intToRomanMap.put(400, "CD");
  intToRomanMap.put(500, "D");
  intToRomanMap.put(900, "CM");
  intToRomanMap.put(1000, "M");
 }

 public static String getRomanString(int number) {
  if (number <= 0) {
   throw new IllegalArgumentException("Support is there only for numbers > 1");
  }

  StringBuilder builder = new StringBuilder();
  while (number != 0) {
   int key = intToRomanMap.floorKey(number);

   String symbol = intToRomanMap.get(key);
   builder.append(symbol);

   number = number - key;
  }

  return builder.toString();
 }
}

RomanGeneratorTest.java
package com.sample.util;

import static org.junit.Assert.assertEquals;

import org.junit.Test;
import static com.sample.util.RomanGenerator.getRomanString;

public class RomanGeneratorTest {

 @Test
 public void getRomanString_positiveInteger_mustMatch() {
  int num1 = 201;
  String symbol1 = "CCI";

  int num2 = 2018;
  String symbol2 = "MMXVIII";

  int num3 = 429;
  String symbol3 = "CDXXIX";

  assertEquals(num1 + " should be equal to " + symbol1, getRomanString(num1), symbol1);
  assertEquals(num2 + " should be equal to " + symbol2, getRomanString(num2), symbol2);
  assertEquals(num3 + " should be equal to " + symbol3, getRomanString(num3), symbol3);

 }

 @Test(expected = IllegalArgumentException.class)
 public void getRomanString_zero_IllegalArgumentException() {
  getRomanString(0);

 }

 @Test(expected = IllegalArgumentException.class)
 public void getRomanString_negative_IllegalArgumentException() {
  getRomanString(-5);

 }
}




No comments:

Post a Comment