פייק

16/09/2021

שאלת תרגול פופולרית בקורסים מבקשת מהתלמידים להמיר מספר מכתיב עשרוני לספרות רומיות. אם אתם לא מכירים את שיטת הספירה הרומית קחו כמה רגעים להיכנס ללינק. אני אחכה.

התרגיל הוא פשוט ועוזר להתאמן על פעולות חילוק במספרים שלמים ושארית. אם נישאר רק עם המספרים הקטנים מ-40 אפשר לנסות את הפיתרון הבא:

symbols = (
        [10, 'X'],
        [5, 'V'],
        [1, 'I' ]
        )

def convert_to_roman(number):
    result = ''
    for i, r in symbols:
        result += r * (number // i)
        number = number % i
    return result

קוד הבדיקה הבא משתמש בפיתרון ומראה שהוא עובד לפחות על 5 מספרים:

result = {
        28: 'XXVIII',
        12: 'XII',
        6: 'VI',
        32: 'XXXII',
        21: 'XXI',
        }

for k, v in result.items():
    if convert_to_roman(k) != v:
        raise Exception(f"Conversion failed for {k}. Expected: '{v}'; Got: '{convert_to_roman(k)}'")

print("All OK")

אבל כשננסה להפעיל את ההמרה על מספר כמו 19 נקבל שגיאה. ההמרה הנכונה של 19 לספירה רומית היא XIX אבל אצלנו הוא יופיע בתור XVIIII. איך מתקנים?

כיוון אחד יכול להיות לנסות לשכנע את המחשב לבדוק כל מיני אפשרויות לבנות את המספרים, ולכתוב את הקוד שמזהה ש 19 הוא 20-1 בדיוק כמו שהוא 15+4 אבל ש 20-1 יותר קצר לכתיבה ולכן כדאי להמיר לזה.

כיוון יותר קל הוא לרמות:

symbols = (
        [10, 'X'],
        [9, 'IX'],
        [5, 'V'],
        [4, 'IV'],
        [1, 'I' ],
        )

אם טבלת הסמלים שלי כוללת גם את 9 ו-4, אז כשהפונקציה תתקל ב 19 היא קודם כל תיקח את ה 10 ותהפוך אותו ל X, ואז את ה 9 שנשאר תהפוך ל IX. הפונקציה לא מספיק חכמה בשביל להבין ש 9 זה עשר פחות אחד, אבל גם לא צריכה להיות. את החוכמה אפשר להשאיר לרומאים.