| (function () { |
| "use strict"; |
|
|
| |
| const dataTypes = [ |
| { name: "float32", bits: 32, bytes: 4 }, |
| { name: "float16", bits: 16, bytes: 2 }, |
| { name: "bfloat16", bits: 16, bytes: 2 }, |
| { name: "8-bit (INT8)", bits: 8, bytes: 1 }, |
| { name: "6-bit (Q_6)", bits: 6, bytes: 0.75 }, |
| { name: "4-bit (Q_4)", bits: 4, bytes: 0.5 }, |
| { name: "3-bit (Q_3)", bits: 3, bytes: 0.375 }, |
| { name: "2-bit (Q_2)", bits: 2, bytes: 0.25 } |
| ]; |
|
|
| |
| const paramInput = document.getElementById('paramInput'); |
| const calculateBtn = document.getElementById('calculateBtn'); |
| const tableBody = document.getElementById('tableBody'); |
| const paramDisplay = document.getElementById('paramDisplay'); |
| const themeToggle = document.getElementById('themeToggle'); |
| const themeIcon = document.getElementById('themeIcon'); |
|
|
| |
| function parseParameters(rawInput) { |
| let cleaned = String(rawInput).replace(/,/g, '').replace(/\s/g, '').trim(); |
| if (cleaned === '') return NaN; |
|
|
| const lower = cleaned.toLowerCase(); |
| let multiplier = 1; |
| let numStr = cleaned; |
|
|
| if (lower.endsWith('b')) { |
| multiplier = 1e9; |
| numStr = cleaned.slice(0, -1); |
| } else if (lower.endsWith('m')) { |
| multiplier = 1e6; |
| numStr = cleaned.slice(0, -1); |
| } |
|
|
| const num = parseFloat(numStr); |
| if (isNaN(num) || num < 0) return NaN; |
|
|
| return num * multiplier; |
| } |
|
|
| |
| function formatNumber(num, decimals = 2) { |
| if (num === undefined || !isFinite(num)) return '—'; |
| return num.toFixed(decimals).replace(/\B(?=(\d{3})+(?!\d))/g, ','); |
| } |
|
|
| function formatBytes(bytes) { |
| if (bytes === undefined || !isFinite(bytes)) return '—'; |
| if (Math.abs(bytes) >= 1e15) { |
| return bytes.toExponential(2); |
| } |
| return formatNumber(bytes, 2); |
| } |
|
|
| function bytesToGB(bytes) { return bytes / 1e9; } |
| function bytesToMiB(bytes) { return bytes / (1024 * 1024); } |
|
|
| |
| function getDataTypeClass(name) { |
| if (name.includes('float')) return 'float'; |
| if (name.includes('8-bit')) return 'int8'; |
| if (name.includes('6-bit')) return 'q6'; |
| if (name.includes('4-bit')) return 'q4'; |
| if (name.includes('3-bit')) return 'q3'; |
| if (name.includes('2-bit')) return 'q2'; |
| return ''; |
| } |
|
|
| |
| function calculateAndRender(rawInput) { |
| const numParams = parseParameters(rawInput); |
|
|
| if (isNaN(numParams)) { |
| tableBody.innerHTML = `<tr><td colspan="5" class="text-center text-danger">Please enter a valid number (e.g., 7B, 1.5b, 100M).</td></tr>`; |
| paramDisplay.textContent = 'Invalid input'; |
| return; |
| } |
|
|
| |
| let displayText = formatNumber(numParams, 0) + ' parameters'; |
| if (numParams >= 1e9) { |
| displayText = (numParams / 1e9).toFixed(2) + 'B parameters'; |
| } else if (numParams >= 1e6) { |
| displayText = (numParams / 1e6).toFixed(2) + 'M parameters'; |
| } |
| paramDisplay.textContent = displayText; |
|
|
| |
| let rowsHtml = ''; |
| dataTypes.forEach(dt => { |
| const bytes = numParams * dt.bytes; |
| const gb = bytesToGB(bytes); |
| const mib = bytesToMiB(bytes); |
| const typeClass = getDataTypeClass(dt.name); |
| rowsHtml += ` |
| <tr data-type="${typeClass}"> |
| <td><strong>${dt.name}</strong></td> |
| <td>${dt.bits}</td> |
| <td>${formatNumber(gb, 2)}</td> |
| <td>${formatNumber(mib, 2)}</td> |
| <td>${formatBytes(bytes)}</td> |
| </tr> |
| `; |
| }); |
| tableBody.innerHTML = rowsHtml; |
| } |
|
|
| |
| calculateBtn.addEventListener('click', function () { |
| calculateAndRender(paramInput.value); |
| }); |
|
|
| paramInput.addEventListener('keydown', function (e) { |
| if (e.key === 'Enter') { |
| e.preventDefault(); |
| calculateAndRender(paramInput.value); |
| } |
| }); |
|
|
| document.querySelectorAll('.btn-preset').forEach(btn => { |
| btn.addEventListener('click', function () { |
| const value = this.getAttribute('data-value'); |
| paramInput.value = value; |
| calculateAndRender(value); |
| }); |
| }); |
|
|
| |
| calculateAndRender(paramInput.value); |
|
|
| |
| function setTheme(theme) { |
| const html = document.documentElement; |
| if (theme === 'dark') { |
| html.classList.add('dark-mode'); |
| themeIcon.textContent = '☀️'; |
| } else { |
| html.classList.remove('dark-mode'); |
| themeIcon.textContent = '🌙'; |
| } |
| localStorage.setItem('theme', theme); |
| } |
|
|
| themeToggle.addEventListener('click', function () { |
| const current = document.documentElement.classList.contains('dark-mode') ? 'dark' : 'light'; |
| setTheme(current === 'dark' ? 'light' : 'dark'); |
| }); |
|
|
| |
| function loadTheme() { |
| const saved = localStorage.getItem('theme'); |
| if (saved) { |
| setTheme(saved); |
| } else { |
| setTheme('dark'); |
| } |
| } |
| loadTheme(); |
| })(); |