🏛️ 羅馬數字轉換器完全指南

📅 發布日期:2025-01-27 ⏱️ 閱讀時間:12 分鐘 🔖 分類:數學工具

深入了解羅馬數字系統的歷史、轉換規則與演算法實作。從基礎符號到特殊情況處理, 掌握羅馬數字與阿拉伯數字互轉技巧,適用於歷史文獻、建築設計等應用場景。

1. 羅馬數字系統與歷史 🏛️

羅馬數字的起源

羅馬數字(Roman Numerals)起源於古羅馬,是一種使用拉丁字母來表示數字的系統。 與現代的阿拉伯數字(位值制)不同,羅馬數字採用累加減法制, 透過符號的組合與位置關係來表達數值。

💡 歷史背景

  • 公元前 500 年:羅馬數字系統在古羅馬城邦形成
  • 中世紀:歐洲廣泛使用於商業、建築、文獻記錄
  • 14 世紀:阿拉伯數字引入歐洲,逐漸取代羅馬數字
  • 現代:仍用於鐘錶、建築年份、書籍章節、電影片尾字幕等

基本符號與數值

羅馬數字使用 7 個基本符號,每個符號對應一個固定數值:

符號 數值 記憶技巧
I 1 一根手指(I = 1)
V 5 手掌張開(V 形)
X 10 雙手交叉(X = 10)
L 50 拉丁文 Libra(50 磅)
C 100 拉丁文 Centum(100)
D 500 半個 M(1000 的一半)
M 1000 拉丁文 Mille(1000)

羅馬數字的特點

✅ 優點

  • 符號直觀,易於雕刻與書寫
  • 不需要「零」的概念
  • 小數值計算較快(如 I、II、III)
  • 具有儀式感和歷史美感

❌ 局限性

  • 無法表示零和負數
  • 無法表示小數和分數
  • 大數運算複雜(如乘除法)
  • 符號組合規則較多,易出錯

2. 快速開始指南 🚀

1

選擇轉換方向

決定要將阿拉伯數字轉羅馬數字,還是羅馬數字轉阿拉伯數字

範例:
  • 阿拉伯 → 羅馬:2024MMXXIV
  • 羅馬 → 阿拉伯:MCMXCIV1994
2

輸入數字或符號

在輸入框中輸入要轉換的數字(1-3999)或羅馬數字符號。

⚠️ 注意:標準羅馬數字只支援 1-3999 的範圍, 超過 3999 需要使用特殊符號(如上劃線表示 ×1000)。
3

驗證輸入合法性

系統會自動檢查輸入是否符合羅馬數字規則:

  • ✅ 只包含合法符號(I, V, X, L, C, D, M)
  • ✅ 符號組合符合減法規則(如 IV, IX, XL)
  • ✅ 沒有超過 3 次連續重複(如 IIII 是錯誤的)
4

執行轉換

點擊「轉換」按鈕,系統會即時顯示轉換結果。

即時範例:
  • 58LVIII(L=50, V=5, III=3)
  • CDXLIV444(CD=400, XL=40, IV=4)
5

查看分解步驟

點擊「顯示步驟」可查看詳細的轉換過程和邏輯:

2024 的轉換步驟:
1. 2000 = MM(M×2)
2. 20 = XX(X×2)
3. 4 = IV(5-1)
結果:MMXXIV

3. 轉換規則與特殊情況 📐

基本規則:累加與減法

羅馬數字的核心規則是累加減法

🔹 規則 1:符號累加

當較大的符號在前,較小的符號在後時,進行累加

  • VI = V + I = 5 + 1 = 6
  • XII = X + I + I = 10 + 1 + 1 = 12
  • LXV = L + X + V = 50 + 10 + 5 = 65

🔹 規則 2:減法記號

當較小的符號在前,較大的符號在後時,進行減法

減法組合 數值 說明
IV 4 5 - 1 = 4
IX 9 10 - 1 = 9
XL 40 50 - 10 = 40
XC 90 100 - 10 = 90
CD 400 500 - 100 = 400
CM 900 1000 - 100 = 900

🔹 規則 3:重複限制

相同符號最多連續出現 3 次(V、L、D 不可重複)。

  • III = 3(合法)
  • IIII = 4(錯誤,應寫作 IV)
  • XXX = 30(合法)
  • XXXX = 40(錯誤,應寫作 XL)

特殊情況處理

🔸 情況 1:減法只能用於特定組合

不是所有小符號都能放在大符號前面。只有以下組合合法:

  • I 只能放在 VX 前面(IV, IX)
  • X 只能放在 LC 前面(XL, XC)
  • C 只能放在 DM 前面(CD, CM)
錯誤範例:IL(49)、IC(99)、XM(990)都是非法的!
正確寫法:49 = XLIX,99 = XCIX,990 = CMXC

🔸 情況 2:零和負數

羅馬數字系統沒有零的概念,也無法表示負數。

  • 零:古羅馬用 nulla(拉丁文「無」)表示
  • 負數:需要額外標註(如 -V 表示 -5)

🔸 情況 3:大數表示(超過 3999)

標準羅馬數字只能表示 1-3999。更大的數需要使用上劃線(表示 ×1000):

  • = 5,000(5 × 1000)
  • = 10,000(10 × 1000)
  • = 50,000(50 × 1000)

4. 演算法實作 💻

阿拉伯數字 → 羅馬數字(貪婪演算法)

轉換策略:使用貪婪演算法(Greedy Algorithm), 從最大的符號組合開始,依次減去對應數值,直到數字變為 0。


function toRoman(num) {
    // 定義符號對照表(包含減法組合)
    const mapping = [
        { value: 1000, symbol: 'M' },
        { value: 900,  symbol: 'CM' },  // 減法組合
        { value: 500,  symbol: 'D' },
        { value: 400,  symbol: 'CD' },  // 減法組合
        { value: 100,  symbol: 'C' },
        { value: 90,   symbol: 'XC' },  // 減法組合
        { value: 50,   symbol: 'L' },
        { value: 40,   symbol: 'XL' },  // 減法組合
        { value: 10,   symbol: 'X' },
        { value: 9,    symbol: 'IX' },  // 減法組合
        { value: 5,    symbol: 'V' },
        { value: 4,    symbol: 'IV' },  // 減法組合
        { value: 1,    symbol: 'I' }
    ];

    let result = '';

    // 貪婪匹配
    for (const { value, symbol } of mapping) {
        while (num >= value) {
            result += symbol;
            num -= value;
        }
    }

    return result;
}

// 測試
console.log(toRoman(2024));  // 輸出: "MMXXIV"
console.log(toRoman(1994));  // 輸出: "MCMXCIV"
console.log(toRoman(444));   // 輸出: "CDXLIV"

⏱️ 時間複雜度分析

  • 時間複雜度:O(1)(最多 13 次迴圈,常數時間)
  • 空間複雜度:O(1)(固定大小的對照表)
  • 優點:簡潔直觀,易於理解和維護

羅馬數字 → 阿拉伯數字(掃描演算法)

轉換策略:從左到右掃描符號,判斷當前符號與下一個符號的關係:
• 如果 current < next,減去當前值(減法規則)
• 否則,加上當前值(累加規則)


function fromRoman(roman) {
    // 定義符號數值表
    const values = {
        'I': 1,
        'V': 5,
        'X': 10,
        'L': 50,
        'C': 100,
        'D': 500,
        'M': 1000
    };

    let result = 0;

    // 從左到右掃描
    for (let i = 0; i < roman.length; i++) {
        const current = values[roman[i]];
        const next = values[roman[i + 1]];

        // 減法規則:當前符號小於下一個符號
        if (next && current < next) {
            result -= current;
        } else {
            result += current;
        }
    }

    return result;
}

// 測試
console.log(fromRoman('MMXXIV'));   // 輸出: 2024
console.log(fromRoman('MCMXCIV'));  // 輸出: 1994
console.log(fromRoman('CDXLIV'));   // 輸出: 444

⏱️ 時間複雜度分析

  • 時間複雜度:O(n)(n = 羅馬數字長度,最多 15 位)
  • 空間複雜度:O(1)(固定大小的符號表)
  • 優點:單次掃描,高效簡潔

轉換步驟可視化範例

1994 轉換為羅馬數字為例:

初始數字: 1994
步驟 1: 1994 >= 1000 → 加入 'M',剩餘 994
步驟 2: 994 >= 900 → 加入 'CM',剩餘 94
步驟 3: 94 >= 90 → 加入 'XC',剩餘 4
步驟 4: 4 >= 4 → 加入 'IV',剩餘 0
結果: MCMXCIV

5. 常見問題 ❓

Q1: 為什麼 4 寫作 IV 而不是 IIII?

這是減法記號的應用。IV(5-1=4)比 IIII 更簡潔。 但在某些古老鐘錶上,仍可見到 IIII 的寫法,這是為了視覺對稱性(與 VIII 對稱)。

現代標準:4 = IV, 9 = IX
古代變體:4 = IIII(鐘錶常見)

Q2: 羅馬數字能表示小數嗎?

標準羅馬數字無法表示小數。古羅馬使用分數系統(如 1/12 稱為 uncia), 但沒有類似現代小數點的概念。現代若需表示小數,通常使用阿拉伯數字。

Q3: 如何驗證羅馬數字是否合法?

使用正則表達式(Regex)進行驗證:


function isValidRoman(roman) {
    // 正則表達式:匹配合法的羅馬數字(1-3999)
    const regex = /^M{0,3}(CM|CD|D?C{0,3})(XC|XL|L?X{0,3})(IX|IV|V?I{0,3})$/;
    return regex.test(roman);
}

console.log(isValidRoman('MCMXCIV'));  // true(合法)
console.log(isValidRoman('IIII'));     // false(不合法)
console.log(isValidRoman('IC'));       // false(不合法的減法組合)

Q4: 羅馬數字轉換器的實際用途有哪些?

現代應用場景包括:

  • 🏛️ 建築設計:建築年份標記(如 MMXXIV = 2024)
  • 📚 出版業:書籍章節編號、前言頁碼
  • 🎬 影視業:電影片尾字幕年份(如 ©MMXXIV)
  • 鐘錶製造:高級手錶錶盤數字
  • 🎓 學術研究:歷史文獻解讀、考古研究

Q5: 羅馬數字轉換有哪些常見錯誤?

初學者常見錯誤:

錯誤寫法 正確寫法 錯誤原因
IIII IV 超過 3 次重複
VV X V 不可重複
IL XLIX 非法減法組合
IC XCIX 非法減法組合

6. 進階技巧與驗證邏輯 🔬

完整驗證系統

實作一個完整的羅馬數字驗證器,包含格式檢查、範圍驗證、規則檢查:


class RomanValidator {
    constructor() {
        this.validSymbols = /^[IVXLCDM]+$/;
        this.validPattern = /^M{0,3}(CM|CD|D?C{0,3})(XC|XL|L?X{0,3})(IX|IV|V?I{0,3})$/;
    }

    validate(roman) {
        const errors = [];

        // 1. 檢查空字串
        if (!roman || roman.trim() === '') {
            errors.push('輸入不能為空');
            return { valid: false, errors };
        }

        // 2. 檢查大小寫(統一轉大寫)
        roman = roman.toUpperCase();

        // 3. 檢查是否包含非法字符
        if (!this.validSymbols.test(roman)) {
            errors.push('包含非法字符(只允許 I, V, X, L, C, D, M)');
        }

        // 4. 檢查組合規則
        if (!this.validPattern.test(roman)) {
            errors.push('符號組合不符合羅馬數字規則');
        }

        // 5. 檢查範圍(1-3999)
        if (errors.length === 0) {
            const value = this.fromRoman(roman);
            if (value < 1 || value > 3999) {
                errors.push(`數值超出範圍(1-3999),當前值:${value}`);
            }
        }

        return {
            valid: errors.length === 0,
            errors: errors,
            value: errors.length === 0 ? this.fromRoman(roman) : null
        };
    }

    fromRoman(roman) {
        const values = { 'I': 1, 'V': 5, 'X': 10, 'L': 50, 'C': 100, 'D': 500, 'M': 1000 };
        let result = 0;
        for (let i = 0; i < roman.length; i++) {
            const current = values[roman[i]];
            const next = values[roman[i + 1]];
            result += (next && current < next) ? -current : current;
        }
        return result;
    }
}

// 測試驗證器
const validator = new RomanValidator();

console.log(validator.validate('MCMXCIV'));
// { valid: true, errors: [], value: 1994 }

console.log(validator.validate('IIII'));
// { valid: false, errors: ['符號組合不符合羅馬數字規則'], value: null }

console.log(validator.validate('IC'));
// { valid: false, errors: ['符號組合不符合羅馬數字規則'], value: null }

雙向轉換整合

將轉換和驗證整合到一個完整的工具類:


class RomanNumerals {
    static toRoman(num) {
        if (num < 1 || num > 3999) {
            throw new Error('數字必須在 1-3999 範圍內');
        }

        const mapping = [
            [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']
        ];

        let result = '';
        for (const [value, symbol] of mapping) {
            while (num >= value) {
                result += symbol;
                num -= value;
            }
        }
        return result;
    }

    static fromRoman(roman) {
        const validator = new RomanValidator();
        const validation = validator.validate(roman);

        if (!validation.valid) {
            throw new Error(`無效的羅馬數字:${validation.errors.join(', ')}`);
        }

        return validation.value;
    }

    static isValid(roman) {
        const validator = new RomanValidator();
        return validator.validate(roman).valid;
    }
}

// 使用範例
try {
    console.log(RomanNumerals.toRoman(2024));      // "MMXXIV"
    console.log(RomanNumerals.fromRoman('MCMXCIV')); // 1994
    console.log(RomanNumerals.isValid('IV'));      // true
    console.log(RomanNumerals.isValid('IIII'));    // false
} catch (error) {
    console.error(error.message);
}

性能優化技巧

💡 快取結果

對於重複查詢,使用 Map 快取轉換結果:


const romanCache = new Map();

function toRomanCached(num) {
    if (romanCache.has(num)) {
        return romanCache.get(num);
    }
    const result = RomanNumerals.toRoman(num);
    romanCache.set(num, result);
    return result;
}

💡 批次轉換

一次處理多個數字,減少函數調用開銷:


function batchToRoman(numbers) {
    return numbers.map(num => ({
        decimal: num,
        roman: RomanNumerals.toRoman(num)
    }));
}

const results = batchToRoman([1, 4, 9, 50, 100, 500, 1000, 2024]);
console.log(results);
// [{ decimal: 1, roman: 'I' }, { decimal: 4, roman: 'IV' }, ...]

7. 實際應用案例 🎯

📚 案例 1:書籍章節自動編號

需求:自動為書籍章節生成羅馬數字編號(前言、目錄等使用羅馬數字)。


class BookChapterNumbering {
    static generateFrontMatter(pages) {
        const chapters = [];
        for (let i = 1; i <= pages; i++) {
            chapters.push({
                page: i,
                romanNumeral: RomanNumerals.toRoman(i),
                section: '前言'
            });
        }
        return chapters;
    }

    static generateTableOfContents(chapters) {
        return chapters.map((title, index) => ({
            chapter: `第 ${RomanNumerals.toRoman(index + 1)} 章`,
            title: title
        }));
    }
}

// 生成前言頁碼(i, ii, iii, iv, v...)
const frontMatter = BookChapterNumbering.generateFrontMatter(10);
console.log(frontMatter);
// [{ page: 1, romanNumeral: 'I', section: '前言' }, ...]

// 生成章節目錄
const chapters = ['緒論', '文獻回顧', '研究方法', '結果與討論', '結論'];
const toc = BookChapterNumbering.generateTableOfContents(chapters);
console.log(toc);
// [{ chapter: '第 I 章', title: '緒論' }, { chapter: '第 II 章', title: '文獻回顧' }, ...]
✅ 應用效果:自動生成標準學術論文格式,前言使用羅馬數字(i-x), 正文使用阿拉伯數字(1-n)。

🏛️ 案例 2:建築年份標記生成器

需求:為建築物、紀念碑生成羅馬數字年份標記(如 MMXXIV)。


class BuildingYearMarker {
    static generateMarker(year, prefix = '©') {
        if (year < 1 || year > 3999) {
            throw new Error('年份必須在 1-3999 範圍內');
        }
        const romanYear = RomanNumerals.toRoman(year);
        return `${prefix} ${romanYear}`;
    }

    static generatePeriodMarker(startYear, endYear) {
        const start = RomanNumerals.toRoman(startYear);
        const end = RomanNumerals.toRoman(endYear);
        return `${start} - ${end}`;
    }
}

// 生成當前年份標記
console.log(BuildingYearMarker.generateMarker(2024));
// "© MMXXIV"

// 生成時期標記(如羅馬帝國:27 BC - 476 AD)
console.log(BuildingYearMarker.generatePeriodMarker(27, 476));
// "XXVII - CDLXXVI"
✅ 應用效果:自動生成建築銘牌、版權標記,增添歷史感和儀式感。 適用於博物館、紀念碑、古建築修復等場景。

🎬 案例 3:電影片尾字幕年份轉換

需求:批次轉換電影製作年份為羅馬數字(電影業標準格式)。


class MovieCreditGenerator {
    static generateCopyright(year, company) {
        const romanYear = RomanNumerals.toRoman(year);
        return `© ${romanYear} ${company}. All Rights Reserved.`;
    }

    static batchGenerate(movies) {
        return movies.map(movie => ({
            ...movie,
            copyrightNotice: this.generateCopyright(movie.year, movie.studio)
        }));
    }
}

const movies = [
    { title: 'The Matrix', year: 1999, studio: 'Warner Bros.' },
    { title: 'Inception', year: 2010, studio: 'Warner Bros.' },
    { title: 'Interstellar', year: 2014, studio: 'Paramount Pictures' }
];

const credits = MovieCreditGenerator.batchGenerate(movies);
console.log(credits);
// [
//   { title: 'The Matrix', year: 1999, studio: 'Warner Bros.',
//     copyrightNotice: '© MCMXCIX Warner Bros. All Rights Reserved.' },
//   ...
// ]
✅ 應用效果:自動化批次處理,確保所有電影片尾字幕格式統一。 符合好萊塢電影業標準。

🚀 立即試用羅馬數字轉換器

體驗完整的羅馬數字轉換功能,支援雙向轉換、即時驗證、步驟分解。

立即使用工具