排列組合計算器技術實作

深入了解排列組合計算器的完整實作,包含 BigInt 大數運算優化、高效階乘算法、自動計算引擎、輸入驗證系統和雙語界面整合

概述

排列組合計算器是一個專為數學學習和統計分析設計的專業計算工具,能夠快速計算排列數 P(n,r) 和組合數 C(n,r)。 本工具採用 BigInt 大數運算技術,徹底解決了 JavaScript 原生數值類型的精度限制問題,可以處理極大的數值計算。 提供自動計算、即時結果顯示、錯誤提示、公式參考等功能,完全在瀏覽器本地運行,確保計算的準確性和隱私安全。

🔢 大數運算支援

使用 JavaScript BigInt 技術,支援超大數值的精確計算,例如 P(170, 85) 等大型排列組合運算,避免數值溢位和精度損失。

技術架構與核心設計

整體架構設計

技術項目 實作方式 設計考量
數值處理 BigInt 大數運算 避免 Number 類型的精度限制
計算引擎 優化的階乘算法 減少重複計算,提升效能
用戶介面 響應式設計 + 自動計算 即時反饋,流暢體驗
錯誤處理 多層次驗證系統 友好的錯誤提示
國際化 完整雙語系統 支援中英文切換

數學公式基礎

排列公式 / Permutation Formula:
P(n, r) = n! / (n - r)!
= n × (n-1) × ... × (n-r+1)

組合公式 / Combination Formula:
C(n, r) = n! / (r! × (n - r)!)
= P(n, r) / r!

特殊情況 / Special Cases:
- P(n, 0) = 1
- C(n, 0) = C(n, n) = 1
- C(n, r) = C(n, n-r) (對稱性)

關鍵功能實現

  • 🔢 BigInt 大數運算:使用 JavaScript BigInt 類型處理超大數值,支援到 n=170 的精確計算
  • ⚡ 自動計算功能:輸入數值後自動觸發計算,無需手動點擊按鈕
  • 🎯 優化算法:使用迭代而非遞迴,避免重複計算,提升性能
  • ✅ 完整驗證系統:檢查輸入合法性、範圍限制、邏輯關係
  • 📋 一鍵複製:支援單個結果或全部結果的快速複製
  • 💡 公式參考:顯示計算公式,幫助理解數學原理
  • 🌐 雙語支援:完整的中英文介面和錯誤提示
  • 📱 響應式設計:適配各種設備螢幕尺寸

⚠️ 使用限制

雖然 BigInt 支援任意精度整數,但為了確保計算效能和避免瀏覽器卡頓,本工具限制 n 的最大值為 170。這個限制足以滿足絕大多數實際應用場景。

完整程式碼實作

以下是排列組合計算器的完整程式碼實作,按功能模組分類展示。點擊卡片標題可展開查看詳細程式碼:

📦 核心排列組合計算器類別

功能:主要的 PermutationCombinationCalculator 類別,包含建構函數、初始化方法和核心配置

/**
 * Permutation & Combination Calculator - Core Implementation
 * 排列組合計算器 - 核心實作
 * 
 * A professional tool for calculating permutations and combinations with BigInt support
 * 使用 BigInt 支援的專業排列組合計算工具
 */
class PermutationCombinationCalculator {
    constructor() {
        // 當前語言設定 / Current language setting
        this.currentLanguage = 'zh';
        
        // 自動計算延遲計時器 / Auto-calculation delay timer
        this.autoCalculateTimeout = null;
        
        // 翻譯字典 / Translation dictionary
        this.translations = {
            zh: {
                pcCalculatorTitle: '🔢 排列組合計算器',
                pcCalculatorDescription: '快速計算排列數 P(n,r) 和組合數 C(n,r)',
                nInputLabel: '輸入 n (總數):',
                rInputLabel: '輸入 r (選取數):',
                nInputPlaceholder: '例如:6',
                rInputPlaceholder: '例如:3',
                calculateBtn: '🔢 計算',
                clearBtn: '❌ 清除',
                copyResultsBtn: '📋 複製結果',
                permutationLabel: '排列 P(n, r):',
                combinationLabel: '組合 C(n, r):',
                copyBtn: '複製',
                formulaTitle: '💡 計算公式',
                permutationFormula: '排列 P(n, r) = n! / (n - r)!',
                combinationFormula: '組合 C(n, r) = n! / (r! × (n - r)!)',
                errorInvalidInput: '請輸入有效的非負整數',
                errorRGreaterThanN: 'r 不可大於 n',
                errorTooLarge: 'n 太大,可能造成計算錯誤(建議 n ≤ 170)',
                copiedToClipboard: '已複製到剪貼簿!',
                copyError: '複製失敗,請手動選取'
            },
            en: {
                pcCalculatorTitle: '🔢 Permutation & Combination Calculator',
                pcCalculatorDescription: 'Fast calculation of permutation P(n,r) and combination C(n,r)',
                nInputLabel: 'Enter n (total items):',
                rInputLabel: 'Enter r (selected items):',
                nInputPlaceholder: 'e.g.: 6',
                rInputPlaceholder: 'e.g.: 3',
                calculateBtn: '🔢 Calculate',
                clearBtn: '❌ Clear',
                copyResultsBtn: '📋 Copy Results',
                permutationLabel: 'Permutation P(n, r):',
                combinationLabel: 'Combination C(n, r):',
                copyBtn: 'Copy',
                formulaTitle: '💡 Formulas',
                permutationFormula: 'Permutation P(n, r) = n! / (n - r)!',
                combinationFormula: 'Combination C(n, r) = n! / (r! × (n - r)!)',
                errorInvalidInput: 'Please enter valid non-negative integers',
                errorRGreaterThanN: 'r cannot be greater than n',
                errorTooLarge: 'n is too large, may cause calculation errors (recommend n ≤ 170)',
                copiedToClipboard: 'Copied to clipboard!',
                copyError: 'Copy failed, please select manually'
            }
        };
        
        // 初始化工具 / Initialize tool
        this.init();
    }
    
    /**
     * 初始化方法
     * Initialization method
     */
    init() {
        // 設置全域語言監聽器 / Setup global language listener
        this.setupGlobalLanguageListener();
        
        // 設置事件監聽器 / Setup event listeners
        this.setupEventListeners();
        
        // 更新語言顯示 / Update language display
        this.updateLanguage();
    }
}

🌐 全域語言系統整合

功能:整合 Tool Master 全域語言切換系統,支援即時雙語切換

/**
 * 設置全域語言監聽器
 * Setup global language listener
 */
setupGlobalLanguageListener() {
    // 監聽語言切換事件 / Listen for language change events
    window.addEventListener('languageChanged', (event) => {
        this.currentLanguage = event.detail.language;
        this.updateLanguage();
    });

    // 檢查全域語言設定 / Check global language setting
    const checkGlobalLanguage = () => {
        if (window.globalI18n) {
            this.currentLanguage = window.globalI18n.currentLanguage;
            this.updateLanguage();
            return true;
        }
        return false;
    };

    // 如果全域語言系統尚未載入,延遲檢查 / If global language system not loaded, delay check
    if (!checkGlobalLanguage()) {
        setTimeout(() => {
            checkGlobalLanguage();
        }, 100);
    }
}

/**
 * 更新語言顯示
 * Update language display
 */
updateLanguage() {
    const t = this.translations[this.currentLanguage];

    // 更新所有帶有 data-i18n 屬性的元素 / Update all elements with data-i18n attributes
    document.querySelectorAll('[data-i18n]').forEach(element => {
        const key = element.getAttribute('data-i18n');
        if (t[key]) {
            element.textContent = t[key];
        }
    });

    // 更新 placeholder 屬性 / Update placeholder attributes
    document.querySelectorAll('[data-i18n-placeholder]').forEach(element => {
        const key = element.getAttribute('data-i18n-placeholder');
        if (t[key]) {
            element.placeholder = t[key];
        }
    });
}

🎯 DOM 初始化與事件處理

功能:設置所有 DOM 元素的事件監聽器,包含按鈕點擊、輸入變化和鍵盤事件

/**
 * 設置事件監聽器
 * Setup event listeners
 */
setupEventListeners() {
    // 計算按鈕點擊事件 / Calculate button click event
    document.getElementById('calculateBtn').addEventListener('click', () => this.calculate());
    
    // 清除按鈕點擊事件 / Clear button click event
    document.getElementById('clearBtn').addEventListener('click', () => this.clear());
    
    // 複製結果按鈕點擊事件 / Copy results button click event
    document.getElementById('copyResultsBtn').addEventListener('click', () => this.copyAllResults());
    
    // Enter 鍵支援 - n 輸入框 / Enter key support - n input
    document.getElementById('nInput').addEventListener('keypress', (e) => {
        if (e.key === 'Enter') this.calculate();
    });
    
    // Enter 鍵支援 - r 輸入框 / Enter key support - r input
    document.getElementById('rInput').addEventListener('keypress', (e) => {
        if (e.key === 'Enter') this.calculate();
    });

    // 自動計算功能 - n 輸入變化 / Auto-calculate on n input change
    document.getElementById('nInput').addEventListener('input', () => {
        clearTimeout(this.autoCalculateTimeout);
        this.autoCalculateTimeout = setTimeout(() => this.autoCalculate(), 500);
    });
    
    // 自動計算功能 - r 輸入變化 / Auto-calculate on r input change
    document.getElementById('rInput').addEventListener('input', () => {
        clearTimeout(this.autoCalculateTimeout);
        this.autoCalculateTimeout = setTimeout(() => this.autoCalculate(), 500);
    });
}

/**
 * 自動計算
 * Auto-calculate
 */
autoCalculate() {
    const n = document.getElementById('nInput').value;
    const r = document.getElementById('rInput').value;
    
    // 只有當兩個輸入都有值時才自動計算 / Only auto-calculate when both inputs have values
    if (n && r) {
        this.calculate();
    }
}

⚙️ 核心計算引擎

功能:使用 BigInt 實現的高效排列組合計算算法,包含優化策略和特殊情況處理

/**
 * BigInt 階乘函數,避免溢位
 * BigInt factorial function to avoid overflow
 */
factorial(n) {
    if (n === 0 || n === 1) return BigInt(1);
    
    let result = BigInt(1);
    for (let i = 2; i <= n; i++) {
        result *= BigInt(i);
    }
    return result;
}

/**
 * 計算排列 P(n,r) = n! / (n-r)!
 * Calculate permutation P(n,r) = n! / (n-r)!
 * 
 * 優化策略:使用迭代計算 n * (n-1) * ... * (n-r+1)
 * Optimization: Use iteration to calculate n * (n-1) * ... * (n-r+1)
 */
permutation(n, r) {
    // 驗證輸入 / Validate input
    if (r > n || n < 0 || r < 0) return null;
    
    // 特殊情況 / Special case
    if (r === 0) return BigInt(1);
    
    // 優化計算:n * (n-1) * ... * (n-r+1)
    // Optimized calculation: n * (n-1) * ... * (n-r+1)
    let result = BigInt(1);
    for (let i = 0; i < r; i++) {
        result *= BigInt(n - i);
    }
    return result;
}

/**
 * 計算組合 C(n,r) = n! / (r! * (n-r)!)
 * Calculate combination C(n,r) = n! / (r! * (n-r)!)
 * 
 * 優化策略:
 * 1. 使用對稱性:C(n,r) = C(n,n-r)
 * 2. 交替乘除避免中間結果過大
 * 
 * Optimization strategies:
 * 1. Use symmetry: C(n,r) = C(n,n-r)
 * 2. Alternate multiplication and division to avoid large intermediate results
 */
combination(n, r) {
    // 驗證輸入 / Validate input
    if (r > n || n < 0 || r < 0) return null;
    
    // 特殊情況 / Special cases
    if (r === 0 || r === n) return BigInt(1);
    
    // 使用較小的 r 進行優化:C(n,r) = C(n,n-r)
    // Use smaller r for optimization: C(n,r) = C(n,n-r)
    r = Math.min(r, n - r);
    
    // 交替乘除計算 / Alternate multiplication and division
    let result = BigInt(1);
    for (let i = 0; i < r; i++) {
        result = result * BigInt(n - i) / BigInt(i + 1);
    }
    return result;
}

🎨 輸入驗證與錯誤處理

功能:完整的輸入驗證系統,包含範圍檢查、類型驗證和友好的錯誤提示

/**
 * 計算主函數
 * Main calculation function
 */
calculate() {
    // 隱藏之前的錯誤訊息 / Hide previous error messages
    this.hideError();
    
    // 獲取輸入值 / Get input values
    const nInput = document.getElementById('nInput').value.trim();
    const rInput = document.getElementById('rInput').value.trim();

    // 驗證輸入是否為空 / Validate if inputs are empty
    if (!nInput || !rInput) {
        this.showError('errorInvalidInput');
        return;
    }

    // 轉換為整數 / Convert to integers
    const n = parseInt(nInput);
    const r = parseInt(rInput);

    // 檢查是否為有效整數 / Check for valid integers
    if (isNaN(n) || isNaN(r) || n < 0 || r < 0 || 
        !Number.isInteger(n) || !Number.isInteger(r)) {
        this.showError('errorInvalidInput');
        return;
    }

    // 檢查 r 是否大於 n / Check if r > n
    if (r > n) {
        this.showError('errorRGreaterThanN');
        return;
    }

    // 檢查數值是否過大 / Check if numbers are too large
    if (n > 170) {
        this.showError('errorTooLarge');
        return;
    }

    try {
        // 執行計算 / Perform calculations
        const permResult = this.permutation(n, r);
        const combResult = this.combination(n, r);

        if (permResult === null || combResult === null) {
            this.showError('errorInvalidInput');
            return;
        }

        // 顯示結果 / Display results
        document.getElementById('permutationResult').textContent = 
            this.formatNumber(permResult);
        document.getElementById('combinationResult').textContent = 
            this.formatNumber(combResult);
        document.getElementById('resultsSection').style.display = 'block';

    } catch (error) {
        console.error('Calculation error:', error);
        this.showError('errorTooLarge');
    }
}

/**
 * 顯示錯誤訊息
 * Show error message
 */
showError(messageKey) {
    const t = this.translations[this.currentLanguage];
    const errorDiv = document.getElementById('errorMessage');
    errorDiv.textContent = t[messageKey];
    errorDiv.style.display = 'block';
    document.getElementById('resultsSection').style.display = 'none';
}

/**
 * 隱藏錯誤訊息
 * Hide error message
 */
hideError() {
    document.getElementById('errorMessage').style.display = 'none';
}

🛠️ 實用方法與輔助功能

功能:數字格式化、清除功能、複製功能和提示訊息等輔助方法

/**
 * 格式化大數字,添加千位分隔符
 * Format large numbers with thousand separators
 */
formatNumber(bigIntNum) {
    return bigIntNum.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',');
}

/**
 * 清除所有輸入和結果
 * Clear all inputs and results
 */
clear() {
    document.getElementById('nInput').value = '';
    document.getElementById('rInput').value = '';
    this.hideError();
    document.getElementById('resultsSection').style.display = 'none';
}

/**
 * 複製所有結果
 * Copy all results
 */
copyAllResults() {
    const t = this.translations[this.currentLanguage];
    const n = document.getElementById('nInput').value;
    const r = document.getElementById('rInput').value;
    const permResult = document.getElementById('permutationResult').textContent;
    const combResult = document.getElementById('combinationResult').textContent;

    // 檢查是否有結果 / Check if there are results
    if (permResult === '-' || combResult === '-') {
        return;
    }

    // 組合結果文字 / Combine result text
    const resultText = `${t.permutationLabel} ${permResult}\n${t.combinationLabel} ${combResult}`;
    
    // 複製到剪貼簿 / Copy to clipboard
    navigator.clipboard.writeText(resultText).then(() => {
        this.showToast(t.copiedToClipboard);
    }).catch(() => {
        this.showToast(t.copyError);
    });
}

/**
 * 顯示提示訊息
 * Show toast message
 */
showToast(message) {
    // 創建提示元素 / Create toast element
    const toast = document.createElement('div');
    toast.textContent = message;
    toast.style.cssText = `
        position: fixed;
        top: 50%;
        left: 50%;
        transform: translate(-50%, -50%);
        background: #333;
        color: white;
        padding: 12px 24px;
        border-radius: 6px;
        z-index: 1000;
        font-size: 14px;
        box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
        animation: fadeIn 0.3s ease;
    `;
    
    // 添加淡入動畫 / Add fade-in animation
    const style = document.createElement('style');
    style.textContent = `
        @keyframes fadeIn {
            from { opacity: 0; transform: translate(-50%, -40%); }
            to { opacity: 1; transform: translate(-50%, -50%); }
        }
    `;
    document.head.appendChild(style);
    
    // 顯示提示 / Show toast
    document.body.appendChild(toast);
    
    // 2秒後移除 / Remove after 2 seconds
    setTimeout(() => {
        document.body.removeChild(toast);
        document.head.removeChild(style);
    }, 2000);
}

🚀 工具初始化與全域函數

功能:工具的啟動程式碼和全域複製函數,確保工具正確初始化

/**
 * 全域複製函數,用於單個結果的複製按鈕
 * Global copy function for individual result copy buttons
 */
function copyToClipboard(elementId) {
    const element = document.getElementById(elementId);
    const text = element.textContent;
    
    // 複製到剪貼簿 / Copy to clipboard
    navigator.clipboard.writeText(text).then(() => {
        // 顯示視覺反饋 / Show visual feedback
        const originalBg = element.style.backgroundColor;
        element.style.backgroundColor = '#4caf50';
        element.style.transition = 'background-color 0.3s ease';
        
        setTimeout(() => {
            element.style.backgroundColor = originalBg;
        }, 300);
    }).catch(() => {
        console.error('Copy failed');
    });
}

/**
 * 工具初始化
 * Tool initialization
 * 
 * 創建排列組合計算器實例
 * Create Permutation & Combination Calculator instance
 */
new PermutationCombinationCalculator();

/**
 * 主要功能列表:
 * Main feature list:
 * 
 * 1. BigInt 大數運算支援 / BigInt large number arithmetic support
 * 2. 排列計算 P(n,r) / Permutation calculation P(n,r)
 * 3. 組合計算 C(n,r) / Combination calculation C(n,r)
 * 4. 自動計算功能 / Auto-calculation feature
 * 5. 輸入驗證 / Input validation
 * 6. 錯誤提示 / Error prompts
 * 7. 結果複製 / Result copying
 * 8. 公式參考 / Formula reference
 * 9. 雙語支援 / Bilingual support
 * 10. 響應式設計 / Responsive design
 */

效能優化策略

算法優化

  • 避免完整階乘計算:排列使用 n×(n-1)×...×(n-r+1) 而非 n!/(n-r)!
  • 利用對稱性:組合計算時選擇較小的 r 值
  • 交替乘除:避免中間結果過大
  • BigInt 優化:只在必要時進行類型轉換

⚡ 效能數據

經過優化後,計算 P(170, 85) 和 C(170, 85) 的時間都在毫秒級別,提供即時響應的使用體驗。

安全性考量

  • 🔒 本地處理:所有計算在瀏覽器本地執行,無數據外洩風險
  • 📊 輸入驗證:嚴格的輸入檢查,防止惡意輸入
  • 🛡️ 範圍限制:限制最大輸入值,防止瀏覽器卡頓
  • ⚠️ 錯誤處理:完善的異常捕獲機制

瀏覽器兼容性

瀏覽器 最低版本 BigInt 支援
Chrome 67+
Firefox 68+
Safari 14+
Edge 79+

📱 行動裝置支援

支援 iOS Safari 14+ 和 Android Chrome 67+。較舊的瀏覽器可能無法使用 BigInt 功能。

未來改進方向

  • 🔄 新增重複排列和重複組合計算
  • 📊 添加結果的視覺化圖表
  • 📱 開發專屬的移動應用程式
  • 🎯 支援多項式係數計算
  • 📚 整合更多組合數學功能
  • 🔗 提供 API 介面供其他應用調用

總結

排列組合計算器展示了如何使用現代 JavaScript 技術構建一個專業的數學計算工具。 通過 BigInt 的應用,我們突破了傳統數值類型的限制,為用戶提供了準確可靠的大數計算能力。 優化的算法設計確保了即使在處理大數時也能保持優秀的性能表現。 這個工具不僅適用於教育學習,也能滿足專業統計分析的需求。

🎯 核心價值

提供準確、快速、易用的排列組合計算服務,助力數學學習和專業應用。