# Play With Code: Converting Roman Numerals With Swift Roman numerals, such as MMXIX, are exciting! In this article, we’re going to write some code that converts any integer number to a roman numeral. It’s a fun, short exercise that touches on many aspects of the Swift programming language. It’s perfect if you have a spare minute or two to play with code!

A big thanks to Les from the United Kingdom, for the inspiration to write this article! Keep having fun coding :-)

## What Are Roman Numerals?

Before we start, let’s do a quick refresher on roman numerals. Roman numerals are a numeric system that originated in ancient Rome. With it, a number like 2019 is written as MMXIX, in letters of the Latin alphabet.

Roman numerals use 7 symbols, each with a fixed integer number:

Symbol I V X L C D M
Value 1 5 10 50 100 500 1000

Roman numerals were used until the late Middle Ages (1500 CE), but in our modern world they still have their uses! You see roman numerals on clocks, paper currency, buildings, monuments, and even movie credits.

The roman numerals system is basically a decimal or “base 10” number system, written from left to right. Instead of each power of ten having its own decimal place, roman numerals “add up” symbols to a given number. It’s easiest to think of them as “tally marks.”

For example, the number 2019 is written as:

• MM for 2 times a thousand
• X for once a ten
• IX for “one before 10”, i.e. 9

That last symbol, IX, is special. Instead of writing VIIII, for “5 + 4 = 9”, you write IX, for “10 – 1 = 9”. This is called “subtractive notation”. It’s quite useful, because it’ll save you from writing lots of symbols! IX is simply shorter than VIIII.

The same trick applies to other symbols too. For example, 40 is XL instead of XXXX, 90 is XC instead of LXXXX, 400 is CD, and 900 is CM. It doesn’t work for non-adjacent symbols, i.e. 999 is not IM but CMXCIX.

#### Learn how to build iOS apps

##### Get started with iOS 13 and Swift 5

Sign up for my iOS development course, and learn how to build great iOS 13 apps with Swift 5 and Xcode 11.

## Setting Up The “roman(number:)” Function

We’re going to write a Swift function that can convert arbitrary integer numbers to roman numerals. Let’s get started!

First, let’s think about the input and output for this function. The function needs an `Int` value as input, and outputs a value of type `String`. So, our function declaration will be this:

``````func roman(number: Int) -> String
{

}
``````

The `roman(number:)` function takes a value of type `Int` for the `number` parameter and outputs a value of type `String`. Perfect!

Next, inside the function, we’re going to define the roman numeral system, like this:

``````let decimals = [1000, 500, 100, 50, 10, 5, 1]
let numerals = ["M", "D", "C", "L", "X", "V", "I"]
``````

The above code defines exactly the same as the table in the previous section. Every decimal value has a roman numeral, such as `C = 100`. Both arrays have exactly the same amount of items, so we can use identical index numbers to look up numerals by decimals.

Two things stand out here:

1. We’ve sorted the arrays from largest-to-smallest. This is crucial for our implementation, as you’ll see later on.
2. We haven’t yet added the IX, CM, etc. “subtractive notation” symbols, which we’ll do later.

Next, we’re coding this inside the function:

``````var result = ""
var number = number
``````

The above code first defines a variable `result` of type `String`. We’re going to use this variable to build up the resulting roman numeral, i.e. the output string.

The local variable `number` is declared with the function parameter `number` (which is a bit ugly). Parameters are constants, so they can’t be changed. By “redeclaring” `number` as a variable, we’re now allowed to change `number`. We couldn’t have used the `inout` keyword here, because that would have produced the unintended side-effect of changing the function’s argument, as you’ll see later on.

Why don’t we use a dictionary for `decimals` and `numerals`? Well, dictionary items don’t have a sort order! The algorithm we’re about to write relies on a larger-to-smaller sort order, which won’t work with dictionaries. An alternative would be using tuples, or sorting the dictionary and decomposing its keys and values – but what we have now is much simpler.

## Converting Numbers To Roman Numerals

Alright, we’re getting to the core of the algorithm. Before we start, it’s worthwhile to consider how we would convert a number to roman numerals with pen and paper. This is always a great idea if you need to design an algorithm.

Here’s how we would convert 1776:

1. See that we need one M, for a thousand – which leaves 776
2. See that we need DCC, for “500 + 100 + 100 = 700”, which leaves 76
3. See that we need LXX, for “50 + 10 + 10 = 70”, which leaves 6
4. Finally, we need VI for “5 + 1 = 6”, resulting in MDCCLXXVI

We could say that we’re subtracting numbers from 1776 until we reach zero. Each number we subtract results in a different symbol added to the final result. Would it be possible to put that workflow into an algorithm?

First, let’s start with a `while` loop. Like this:

``````while number > 0
{

}
``````

This loop will keep iterating for as long as `number` is greater than `0`. Differently said, it’ll stop if `number` is zero. We don’t know how many iterations we need, so we’re using `while` instead of a for loop.

Next, we want to loop over every item in the `decimals` array. We’re going to attempt to subtract this decimal number from `number`. That’s why we sorted the `decimals` array from largest-to-smallest, so we can see if a decimal would “fit into” the input number.

So, we write this inside the `while` loop:

``````for (index, decimal) in decimals.enumerated()
{
if number - decimal >= 0 {

}
}
``````

The for loop is used to iterate over the `decimals` array. We’re using the `enumerated()` function so we can access both the array index and the array value, with the `index` and `decimal` constants in the tuple.

Inside the for loop, we’re checking if `number` minus `decimal` is greater or equal to zero, with an if block. This is exactly what we did in our pen-and-paper workflow, earlier.

• Take for example the `1000 = M` for `number = 1776`. Is 1776 minus 1000 greater than zero? Yes it is! We now know that 1776 can accommodate one M for its thousand.
• Another example: `500 = D` for `number = 99`. Is 99 minus 500 greater than zero? No it’s not! We now know that the number 99 doesn’t include a D.

Let’s finish the code by writing the following inside the `if` block:

``````number -= decimal
result += numerals[index]
break
``````

Here’s what happens on those 3 lines:

1. `decimal` is subtracted from `number`. When we’ve found that a decimal “fits in” the input number, we’ve found a roman numeral, so that decimal can be subtracted from the input number.
2. `numerals[index]` is appended to `result`, so the found roman numeral in the iteration is written down by using `index`. Remember that `index` corresponds to the index number of both the decimal and the roman numeral!
3. `break` exits this iteration of the `for` loop, because we’ve found a roman literal, and thus the `while` loop continues with its next iteration

Finally, we return the resulting value in the function with:

``````return result
``````

Here’s the complete code once more:

``````func roman(number: Int) -> String
{
let decimals = [1000, 500, 100, 50, 10, 5, 1]
let numerals = ["M", "D", "C", "L", "X", "V", "I"]

var result = ""
var number = number

while number > 0
{
for (index, decimal) in decimals.enumerated()
{
if number - decimal >= 0 {
number -= decimal
result += numerals[index]
break
}
}
}

return result
}
``````

Let’s go over the core principles of the algorithm.

• The `while` loop ensures that we’re iterating for as long as `number` is greater than `0`. If `number` equals `0`, the algorithm stops. The code that subtracts something from `number`, is inside the `for` loop: `number -= decimal`. When we’ve found a roman numeral, we’re subtracting its value, to move towards zero.
• The `for` loop, and its inner `if` block, is what checks every decimal against the current `number` value. It’s as if it’s trying to “fit” a roman numeral inside the number. Because, if it fits, we’ve got a match!
• When the algorithm finds a roman numeral, for example M for a 1000 in 1776, it’ll subtract that decimal from `number` and append the numeral to `result`. The loop also needs to be broken with `break`, because the loop needs to start over from the beginning.

You can see the algorithm do its work more clearly, by adding the following line inside the `if` block:

``````print("Found \(numerals[index]) for \(decimal)")
``````

You can run the function with the following code:

``````print(roman(number: 2019))
print(roman(number: 1776))
print(roman(number: 1999))
``````

For the year 2019, the output is:

``````Found M for 1000
Found M for 1000
Found X for 10
Found V for 5
Found I for 1
Found I for 1
Found I for 1
Found I for 1
``````

But… what’s going on there!? Wasn’t 2019 supposed to be MMXIX?

## Taking Numerals Like “IX” Into Account

We haven’t yet incorporated subtractive notation in our algorithm. We discussed before that some symbols, such as for 9, are written as IX or “one before 10”, instead of VIIII.

The algorithm we’ve coded so far works by attempting to subtract decimals from the input value, substituting them for roman numerals. We could adjust the algorithm to incorporate numerals like IX with some complicated code, but as it turns out, supporting subtractive notation is incredibly simple.

Replace the declaration at the top of the function with:

``````let decimals = [1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1]
let numerals = ["M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I"]
``````

Instead of only using the basic values M, D, C, L, X, V, and I, we’ve simply added the other symbols, like CM, to the array as well. For our algorithm, it doesn’t matter much if you subtract 900, or 500 and 4 times 100! As long as the decimals and numerals are in descending order, the subtraction mechanism works perfectly fine.

And that’s everything there’s to it! Here, try out the code for yourself with this Swift sandbox:

Awesome! We’ve converted any arbitrary decimal value to roman numerals. It’s a fun, short programming exercise that touches on many interesting parts of Swift syntax.

But… what about converting numerals back to integer values? We’ll leave that for another day! If you’re up for a challenge, however, try to find the longest roman numeral between 1 and 3000.

#### Learn how to build iOS apps

##### Get started with iOS 13 and Swift 5

Sign up for my iOS development course, and learn how to build great iOS 13 apps with Swift 5 and Xcode 11. Hi, I'm Reinder.
I help developers play with code.

## Browse Topics

### Reinder de Vries

Reinder de Vries is a professional iOS developer. He teaches app developers how to build their own apps at LearnAppMaking.com. Since 2009 he has developed a few dozen apps for iOS, worked for global brands and lead development at several startups. When he’s not coding, he enjoys strong espresso and traveling.