CODE-0004 · grok-4.5 (low)
def int_to_roman(n):
    if not isinstance(n, int) or isinstance(n, bool) or n < 1 or n > 3999:
        raise ValueError("integer must be in range 1..3999")
    vals = (1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1)
    syms = ("M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I")
    parts = []
    for v, s in zip(vals, syms):
        if n >= v:
            count, n = divmod(n, v)
            parts.append(s * count)
    return "".join(parts)


def roman_to_int(s):
    if not isinstance(s, str) or not s:
        raise ValueError("empty or invalid Roman numeral")
    values = {"I": 1, "V": 5, "X": 10, "L": 50, "C": 100, "D": 500, "M": 1000}
    total = 0
    i = 0
    length = len(s)
    while i < length:
        c = s[i]
        if c not in values:
            raise ValueError("malformed or non-canonical Roman numeral")
        if i + 1 < length:
            n = s[i + 1]
            if n not in values:
                raise ValueError("malformed or non-canonical Roman numeral")
            if values[c] < values[n]:
                total += values[n] - values[c]
                i += 2
                continue
        total += values[c]
        i += 1
    if total < 1 or total > 3999 or int_to_roman(total) != s:
        raise ValueError("malformed or non-canonical Roman numeral")
    return total