CODE-0004 · claude-haiku-4-5 (default)def int_to_roman(n: int) -> str:
"""Convert an integer (1-3999) to canonical Roman numeral notation."""
if not isinstance(n, int) or n < 1 or n > 3999:
raise ValueError(f"Integer must be in range 1..3999, got {n}")
# Mapping of values to Roman numerals in descending order
# Including subtractive forms
val_to_roman = [
(1000, 'M'),
(900, 'CM'),
(500, 'D'),
(400, 'CD'),
(100, 'C'),
(90, 'XC'),
(50, 'L'),
(40, 'XL'),
(10, 'X'),
(9, 'IX'),
(5, 'V'),
(4, 'IV'),
(1, 'I'),
]
result = []
for value, numeral in val_to_roman:
count = n // value
if count:
result.append(numeral * count)
n -= value * count
return ''.join(result)
def roman_to_int(s: str) -> int:
"""Convert a canonical Roman numeral string to an integer (1-3999)."""
if not s:
raise ValueError("Empty string is not a valid Roman numeral")
# Mapping of Roman numerals to their values
roman_to_val = {
'I': 1,
'V': 5,
'X': 10,
'L': 50,
'C': 100,
'D': 500,
'M': 1000,
}
# Valid subtractive pairs in canonical notation
valid_subtractive = {
'IV': 4,
'IX': 9,
'XL': 40,
'XC': 90,
'CD': 400,
'CM': 900,
}
# Check for invalid characters
for char in s:
if char not in roman_to_val:
raise ValueError(f"Invalid character '{char}' in Roman numeral")
result = 0
i = 0
while i < len(s):
# Check for two-character subtractive forms
if i + 1 < len(s):
two_char = s[i:i+2]
if two_char in valid_subtractive:
result += valid_subtractive[two_char]
i += 2
continue
# Check for invalid subtractive combinations
if roman_to_val[s[i]] < roman_to_val[s[i+1]]:
raise ValueError(f"Invalid subtractive form '{two_char}' in Roman numeral")
# Single character
result += roman_to_val[s[i]]
i += 1
# Verify the result is in valid range
if result < 1 or result > 3999:
raise ValueError(f"Roman numeral represents value {result} outside range 1..3999")
# Verify canonicality by converting back and comparing
if int_to_roman(result) != s:
raise ValueError(f"Roman numeral '{s}' is not in canonical form")
return result