← homeProgramming (Програмування)

Task: Convert a Roman numeral to decimal (Ruby)

Learn how to convert a Roman numeral to a decimal using Ruby. A simple and effective solution to the problem with an explanation of the algorithm's principles and tests in RSpec. Suitable for beginners and practice be...

Table of contentsClick link to navigate to the desired location
This content has been automatically translated from Ukrainian.
Let's consider a simple solution to the problem of converting a Roman numeral to a decimal (Ruby).

Condition

Create a function solution that takes a string — a Roman numeral — and returns its value as a decimal integer.
No validation of the correctness of the Roman notation is required.
Examples:
  • "MCMXC" → 1990
  • "MMVIII" → 2008
  • "MDCLXVI" → 1666

How does the conversion of Roman numerals to decimals work?

Roman numerals are a numeral system based on symbols, each corresponding to a certain value: I — 1, V — 5, X — 10, L — 50, C — 100, D — 500, M — 1000. To write a number, the symbols are combined according to certain rules. If a symbol of lesser value stands before a greater one (for example, IV), it means subtraction (5 - 1 = 4). Conversely, if the greater symbol stands before the lesser one, they are added (VI = 5 + 1 = 6). This logic allows for compact representation of both simple and complex numbers, such as MCMXC for 1990.
When converting Roman numerals to decimals, the computer algorithm processes the characters of the string from right to left. This makes it easy to determine whether to add or subtract the value of the symbol. For example, in XIV, processing starts with V = 5, then I = 1 (less than V, so we subtract: 5 - 1 = 4), then X = 10 (greater than I, so we add: 10 + 4 = 14). This approach allows for efficient implementation of the conversion even in a few lines of code.

Test (rspec) to check the method

RSpec.describe '#solution' do
  it 'converts simple Roman numerals' do
    expect(solution('I')).to eq(1)
    expect(solution('III')).to eq(3)
    expect(solution('VIII')).to eq(8)
  end

  it 'converts compound Roman numerals' do
    expect(solution('IV')).to eq(4)
    expect(solution('IX')).to eq(9)
    expect(solution('XL')).to eq(40)
    expect(solution('XC')).to eq(90)
  end

  it 'converts large Roman numerals' do
    expect(solution('MCMXC')).to eq(1990)
    expect(solution('MMVIII')).to eq(2008)
    expect(solution('MDCLXVI')).to eq(1666)
    expect(solution('MMMCMXCIX')).to eq(3999)
  end
end

Method solution

One of the solutions (using Ruby, the same things can be done in many ways).
def solution(roman)
  values = {
    'M' => 1000,
    'D' => 500,
    'C' => 100,
    'L' => 50,
    'X' => 10,
    'V' => 5,
    'I' => 1
  }

  total = 0
  prev = 0

  roman.chars.reverse.each do |char|
    current = values[char]
    if current < prev
      total -= current
    else
      total += current
      prev = current
    end
  end

  total
end

How the algorithm works

We move from the end of the string, adding the values of the symbols. If the current number is less than the previous one, we subtract it; otherwise, we add it. This allows for correct handling of cases like IV or CM.

🔥 More posts

All posts