-
Notifications
You must be signed in to change notification settings - Fork 11
/
integertoroman.go
36 lines (33 loc) · 1.6 KB
/
integertoroman.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
package conversion
import (
"errors"
)
var (
// lookup arrays used for converting from an int to a roman numeral extremely quickly.
r0 = []string{"", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX"} // 1 - 9
r1 = []string{"", "X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC"} // 10 - 90
r2 = []string{"", "C", "CC", "CCC", "CD", "D", "DC", "DCC", "DCCC", "CM"} // 100 - 900
r3 = []string{"", "M", "MM", "MMM"} // 1,000 - 3,000
)
// IntToRoman converts an integer value to a roman numeral string. An error is
// returned if the integer is not between 1 and 3999.
func IntToRoman(n int) (string, error) {
if n < 1 || n > 3999 {
return "", errors.New("integer must be between 1 and 3999")
}
// Concatenate strings for each of 4 lookup array categories.
//
// Key behavior to note here is how math with integers is handled. Values are floored to the
// nearest int, not rounded up. For example, 26/10 = 2 even though the actual result is 2.6.
//
// For example, lets use an input value of 126:
// `r3[n%1e4/1e3]` --> 126 % 10_000 = 126 --> 126 / 1_000 = 0.126 (0 as int) --> r3[0] = ""
// `r2[n%1e3/1e2]` --> 126 % 1_000 = 126 --> 126 / 100 = 1.26 (1 as int) --> r2[1] = "C"
// `r1[n%100/10]` --> 126 % 100 = 26 --> 26 / 10 = 2.6 (2 as int) --> r1[2] = "XX"
// `r0[n%10]` --> 126 % 10 = 6 --> r0[6] = "VI"
// FINAL --> "" + "C" + "XX" + "VI" = "CXXVI"
//
// This is efficient in Go. The 4 operands are evaluated,
// then a single allocation is made of the exact size needed for the result.
return r3[n%1e4/1e3] + r2[n%1e3/1e2] + r1[n%100/10] + r0[n%10], nil
}