I had the task of creating a method or class that receives Arabic numerals and returns Roman numerals. Let's solve it using Ruby.
Roman numerals
I only see Roman numerals like fashionable watches. How do you represent numbers over 12?
The correspondence table between Arabic numerals and Roman numerals is shown below with reference to Roman numerals & # x2013; Wikipedia.
Arabic numerals | Roman numerals |
---|---|
1 | I |
5 | V |
10 | X |
50 | L |
100 | C |
500 | D |
1000 | M |
The numbers in each digit are decomposed into the sum of the above numbers and written in descending order.
For example, 3 is III
, 2020 is MMXX
.
However, Roman numerals have troublesome rules, Generally, when representing numbers like 4 and 99, they are not represented like IIII and LXXXXVIIII.
Such numbers follow the rule of subtraction, which writes a small number to the left of a large number to mean subtracting from right to left. Specifically, 4 is IV
and 99 is XCIX
. Masu.
Also, due to these rules, Roman numerals can only represent values from 1 to 3999. (Did the ancient Romans have trouble with this usage?)
Ruby
From the information so far, let's implement the conversion from Arabic numerals to Roman numerals in Ruby.
If you implement it without any twist, you can do it by using a lot of conditional branches. However, such a program will be hard to see, and over time it will become a moving swelling-like program.
So, I'm going to make a Ruby program with a little ingenuity.
Finding the law is the way to make a program that is easy to read. If you create a method using the law, you can use it to create an easy-to-read program.
So what is the law of Roman numerals?
Looking at the correspondence table above, the letters of the Roman numerals change five times as many as each number, and then when the number is twice as many, it repeats alternately (although up to three times).
From this, we can find out which Roman numeral should be converted by finding the quotient and remainder of 5 and 2 for each digit.
The following shows the behavior when the Arabic numeral is 87
. (Sorry for the confusing explanation and table & # x2026;)
divisor | quotient | Surplus | Roman numerals to convert |
---|---|---|---|
5 | 17 | 2 | I |
2 | 8 | 1 | V |
5 | 1 | 3 | X |
2 | 0 | 1 | L |
5 | 0 | 0 | C |
2 | 0 | 0 | D |
0 | M |
From the table, the Arabic numeral 87
can be expressed as L1, X3, V1, I2, that is, ** LXXXVII
**. This is the correct notation.
I will implement it based on this
class Integer
def to_roman
@@arabic = self
@@roman = ''
@@a2r = []
@@symbol = ['I', 'V', 'X', 'L', 'C', 'D', 'M']
for i in 1..3 do
devide(5)
devide(2)
end
for i in 1..6 do
@@roman = @@symbol[i]*@@a2r[i] + @@roman
end
@@roman = @@symbol[-1]*@@arabic + @@roman
end
def devide n
@@a2r << @@arabic % n
@@arabic /= n
end
end
However, if the above rule is adopted as it is, IIII
will be returned at 4.
So we also have to find a law that corresponds to the subtraction law.
First, let's think about ** concrete numbers **.
It's easy to think of it as a single digit number, so let's consider the Roman numeral conversion between 4
and 9
.
If the Arabic numeral to be converted is 4, it will be IV
, and if it is 9, it will be IX
.
Did you notice that the first Roman numeral is ** I
** in common?
Also, the difference between the two is the Roman numeral behind, ** V
** which represents 5 in 4, and ** X
** which represents 10 in 9.
Let's treat it with numbers to make it easier to find the law. What they have in common in numbers is that both 4 and 9 have a remainder of 5 of 4, and the difference is that the quotient of 5 is 0 for 4 and 1 for 9.
This seems to be able to be incorporated into the above rough law. More generalized, if the remainder of 5 for each digit is 4,
--If the remainder of the next 2 is 0, the Roman numeral on the right is the Roman numeral one before the Roman numeral on the left (e.g. I → V). --If the remainder of the next 2 is 1, the Roman numeral on the right is the Roman numeral one before the Roman numeral on the left (e.g. I → X).
Will be.
Now, let's implement it by incorporating this detailed law.
Code
roman_number.rb
class Integer
def to_roman
@@arabic = self
@@roman = ''
@@a2r = []
@@symbol = ['I', 'V', 'X', 'L', 'C', 'D', 'M']
for i in 0..2 do
devide(5)
devide(2)
k = 2*i
if @@a2r[k] == 4
tmp = @@a2r[k+1]
@@roman = @@symbol[k] + @@symbol[k+1+tmp] + @@roman
else
@@roman = @@symbol[k+1]*@@a2r[k+1] + @@symbol[k]*@@a2r[k] + @@roman
end
end
@@roman = @@symbol[-1]*@@arabic + @@roman
end
def devide n
@@a2r << @@arabic % n
@@arabic /= n
end
end
It's longer than I expected, but I managed to implement it.
Test
Since it is troublesome to check manually, I would like to use the assert \ _equal function created in this article for testing.
Below is the test code
test_rn.rb
require './roman_number'
require './assert_equal'
[
['I', 1],
['II', 2],
['III', 3],
['IV', 4],
['V', 5],
['VI', 6],
['IX', 9],
['X', 10],
['XI', 11],
['XIV', 14],
['XV', 15],
['XIX', 19],
['XXXVIII', 38],
['XLII', 42],
['XLIX', 49],
['LI', 51],
['XCVII', 97],
['XCIX', 99],
['CDXXXIX', 439],
['CDLXXXIII', 483],
['CDXCIX', 499],
['DCCXXXII', 732],
['CMLXI', 961],
['CMXCIX', 999],
['MCMXCIX', 1999]
].each do |expected, index|
assert_equal(expected, index.to_roman)
end
Let's test it.
> ruby test_rn.rb
Now the output is & # x2026;
expected :: I
result :: I
succeeded in assert_equal.
expected :: II
result :: II
succeeded in assert_equal.
expected :: III
result :: III
succeeded in assert_equal.
expected :: IV
result :: IV
succeeded in assert_equal.
expected :: V
result :: V
succeeded in assert_equal.
expected :: VI
result :: VI
succeeded in assert_equal.
expected :: IX
result :: IX
succeeded in assert_equal.
expected :: X
result :: X
succeeded in assert_equal.
expected :: XI
result :: XI
succeeded in assert_equal.
expected :: XIV
result :: XIV
succeeded in assert_equal.
expected :: XV
result :: XV
succeeded in assert_equal.
expected :: XIX
result :: XIX
succeeded in assert_equal.
expected :: XXXVIII
result :: XXXVIII
succeeded in assert_equal.
expected :: XLII
result :: XLII
succeeded in assert_equal.
expected :: XLIX
result :: XLIX
succeeded in assert_equal.
expected :: LI
result :: LI
succeeded in assert_equal.
expected :: XCVII
result :: XCVII
succeeded in assert_equal.
expected :: XCIX
result :: XCIX
succeeded in assert_equal.
expected :: CDXXXIX
result :: CDXXXIX
succeeded in assert_equal.
expected :: CDLXXXIII
result :: CDLXXXIII
succeeded in assert_equal.
expected :: CDXCIX
result :: CDXCIX
succeeded in assert_equal.
expected :: DCCXXXII
result :: DCCXXXII
succeeded in assert_equal.
expected :: CMLXI
result :: CMLXI
succeeded in assert_equal.
expected :: CMXCIX
result :: CMXCIX
succeeded in assert_equal.
expected :: MCMXCIX
result :: MCMXCIX
succeeded in assert_equal.
All successful! You got the results you expected.
Recommended Posts