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