Untitled

 avatar
unknown
html
a month ago
14 kB
3
Indexable
<!DOCTYPE html>
<html lang="uk">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Лабораторна робота 1 — Варіант 4</title>
<style>
  * { box-sizing: border-box; margin: 0; padding: 0; }
  body { font-family: Arial, sans-serif; background: #f5f5f5; color: #222; padding: 24px; }
  h1 { font-size: 20px; font-weight: 600; margin-bottom: 4px; }
  .subtitle { font-size: 13px; color: #666; margin-bottom: 24px; }
  .controls { display: flex; align-items: center; gap: 16px; flex-wrap: wrap; margin-bottom: 24px; background: #fff; padding: 16px; border-radius: 8px; border: 1px solid #e0e0e0; }
  .controls label { font-size: 14px; color: #555; }
  .controls input { padding: 6px 10px; border: 1px solid #ccc; border-radius: 6px; font-size: 14px; width: 100px; }
  button { padding: 8px 20px; background: #1a73e8; color: #fff; border: none; border-radius: 6px; font-size: 14px; cursor: pointer; }
  button:hover { background: #1558b0; }
  .info-bar { background: #e8f0fe; border-radius: 6px; padding: 10px 14px; font-size: 13px; color: #1a73e8; margin-bottom: 24px; }
  .section { margin-bottom: 28px; }
  .section-title { font-size: 13px; font-weight: 600; color: #555; text-transform: uppercase; letter-spacing: 0.05em; margin-bottom: 10px; }
  .metric-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap: 12px; }
  .metric { background: #fff; border: 1px solid #e0e0e0; border-radius: 8px; padding: 14px 16px; }
  .metric-label { font-size: 12px; color: #888; margin-bottom: 4px; }
  .metric-value { font-size: 24px; font-weight: 600; color: #222; }
  .metric-sub { font-size: 11px; margin-top: 4px; }
  .badge-ok { background: #e6f4ea; color: #137333; padding: 2px 8px; border-radius: 4px; font-size: 11px; font-weight: 600; }
  .badge-warn { background: #fce8e6; color: #c5221f; padding: 2px 8px; border-radius: 4px; font-size: 11px; font-weight: 600; }
  table { width: 100%; border-collapse: collapse; background: #fff; border-radius: 8px; overflow: hidden; border: 1px solid #e0e0e0; }
  thead { background: #f8f9fa; }
  th { padding: 8px 12px; font-size: 12px; font-weight: 600; color: #555; text-align: left; border-bottom: 1px solid #e0e0e0; }
  td { padding: 7px 12px; font-size: 13px; border-bottom: 1px solid #f0f0f0; font-family: monospace; }
  tr:last-child td { border-bottom: none; }
  .bits-box { background: #fff; border: 1px solid #e0e0e0; border-radius: 8px; padding: 14px; font-family: monospace; font-size: 12px; line-height: 1.9; word-break: break-all; color: #555; }
  .bits-box span { color: #1a73e8; font-weight: 700; }
  .detail-box { background: #fff; border: 1px solid #e0e0e0; border-radius: 8px; padding: 16px; }
  .row { display: flex; justify-content: space-between; align-items: center; padding: 7px 0; border-bottom: 1px solid #f0f0f0; font-size: 14px; }
  .row:last-child { border-bottom: none; }
  .row-label { color: #666; }
  .row-value { font-family: monospace; font-weight: 600; color: #222; }
  .chart-wrap { position: relative; height: 260px; background: #fff; border: 1px solid #e0e0e0; border-radius: 8px; padding: 16px; }
  .formula { background: #f8f9fa; border-left: 3px solid #1a73e8; padding: 10px 14px; border-radius: 0 6px 6px 0; font-family: monospace; font-size: 14px; color: #333; margin: 8px 0 16px; }
</style>
</head>
<body>

<h1>Лабораторна робота 1 — Варіант 4</h1>
<p class="subtitle">Конгруентний генератор ПВДП | 16-біт | Лінійна складність (Berlekamp-Massey)</p>

<div class="controls">
  <div style="display:flex;align-items:center;gap:8px;">
    <label>X₀ (seed):</label>
    <input type="number" id="seed" value="42" min="1" max="6074">
  </div>
  <div style="display:flex;align-items:center;gap:8px;">
    <label>Кількість бітів n:</label>
    <input type="number" id="nBits" value="10000" min="100" max="10000" step="100">
  </div>
  <button onclick="runAll()">Згенерувати</button>
</div>

<div class="info-bar">
  Варіант 4 &nbsp;|&nbsp; Конгруентний генератор &nbsp;|&nbsp;
  Формула: Xᵢ = (Xᵢ₋₁ · 106 + 1283) mod 6075 &nbsp;|&nbsp;
  Біт = Xᵢ mod 2
</div>

<!-- Метрики -->
<div class="section">
  <div class="section-title">Результати</div>
  <div class="metric-grid">
    <div class="metric">
      <div class="metric-label">Згенеровано бітів</div>
      <div class="metric-value" id="m-n">—</div>
    </div>
    <div class="metric">
      <div class="metric-label">Частотний тест t₁</div>
      <div class="metric-value" id="m-t1">—</div>
      <div class="metric-sub" id="m-t1-sub"></div>
    </div>
    <div class="metric">
      <div class="metric-label">Диференційний тест t₂</div>
      <div class="metric-value" id="m-t2">—</div>
      <div class="metric-sub" id="m-t2-sub"></div>
    </div>
    <div class="metric">
      <div class="metric-label">Лінійна складність L</div>
      <div class="metric-value" id="m-L">—</div>
      <div class="metric-sub" id="m-L-sub"></div>
    </div>
  </div>
</div>

<!-- Таблиця перших 20 -->
<div class="section">
  <div class="section-title">Перші 20 чисел Xᵢ та бітів</div>
  <table>
    <thead>
      <tr>
        <th>i</th>
        <th>Xᵢ₋₁ (попереднє)</th>
        <th>Xᵢ = (Xᵢ₋₁·106 + 1283) mod 6075</th>
        <th>Біт = Xᵢ mod 2</th>
      </tr>
    </thead>
    <tbody id="table-body"></tbody>
  </table>
</div>

<!-- Перегляд бітів -->
<div class="section">
  <div class="section-title">Перші 200 бітів послідовності</div>
  <div class="bits-box" id="bits-preview">—</div>
</div>

<!-- Деталі тестів -->
<div class="section">
  <div class="section-title">Частотний тест</div>
  <div class="formula">t₁ = (1/n) · Σxⱼ,  j=1..n</div>
  <div class="detail-box" id="freq-details"></div>
</div>

<div class="section">
  <div class="section-title">Диференційний тест</div>
  <div class="formula">t₂ = (1/(n-1)) · Σ(xⱼ ⊕ xⱼ₋₁),  j=2..n</div>
  <div class="detail-box" id="diff-details"></div>
</div>

<div class="section">
  <div class="section-title">Лінійна складність — алгоритм Berlekamp-Massey</div>
  <div class="formula">Знаходить найкоротший LFSR що відтворює послідовність. Ідеально: L ≈ n/2</div>
  <div class="detail-box" id="bm-details"></div>
</div>

<!-- Висновок -->
<div class="section">
  <div class="section-title">Висновок</div>
  <div class="detail-box" id="conclusion" style="font-size:14px; line-height:1.7; color:#333;"></div>
</div>
<script>
let chartInst = null;

function generate(seed, n) {
  const a = 106, b = 1283, m = 6075;
  const xs = new Array(n + 1);
  const bits = new Uint8Array(n);
  xs[0] = seed;
  for (let i = 1; i <= n; i++) {
    xs[i] = (xs[i - 1] * a + b) % m;
    bits[i - 1] = xs[i] & 1;
  }
  return { xs, bits };
}

function freqTest(bits) {
  let s = 0;
  for (let i = 0; i < bits.length; i++) s += bits[i];
  return s / bits.length;
}

function diffTest(bits) {
  let s = 0;
  for (let i = 1; i < bits.length; i++) s += bits[i] ^ bits[i - 1];
  return s / (bits.length - 1);
}

function berlekampMassey(bits) {
  const n = bits.length;
  let C = [1], B = [1], L = 0, x = 1;
  const steps = [];

  for (let N = 0; N < n; N++) {
    let d = bits[N];
    for (let j = 1; j < C.length; j++) {
      if (N >= j) d ^= C[j] & bits[N - j];
    }
    d &= 1;

    if (d === 0) {
      x++;
    } else if (2 * L > N) {
      const newC = [...C];
      while (newC.length < B.length + x) newC.push(0);
      for (let i = 0; i < B.length; i++) newC[i + x] ^= B[i];
      C = newC;
      x++;
      if (steps.length < 12) steps.push({ N, d, L, action: 'корекція C(D), L не змінюється', poly: polyStr(C) });
    } else {
      const T = [...C];
      while (C.length < B.length + x) C.push(0);
      for (let i = 0; i < B.length; i++) C[i + x] ^= B[i];
      B = T;
      L = N + 1 - L;
      x = 1;
      if (steps.length < 12) steps.push({ N, d, L, action: 'L збільшено', poly: polyStr(C) });
    }
  }
  return { L, C, steps };
}

function polyStr(C) {
  const sup = n => String(n).split('').map(c => '⁰¹²³⁴⁵⁶⁷⁸⁹'[+c]).join('');
  const terms = [];
  for (let i = C.length - 1; i >= 0; i--) {
    if (!C[i]) continue;
    if (i === 0) terms.push('1');
    else if (i === 1) terms.push('D');
    else terms.push('D' + sup(i));
  }
  return terms.join(' + ') || '0';
}

function badge(ok) {
  return `<span class="${ok ? 'badge-ok' : 'badge-warn'}">${ok ? 'добре ✓' : 'слабко ✗'}</span>`;
}

function row(label, value) {
  return `<div class="row"><span class="row-label">${label}</span><span class="row-value">${value}</span></div>`;
}

function runAll() {
  const seed = parseInt(document.getElementById('seed').value);
  const n    = parseInt(document.getElementById('nBits').value) || 10000;

  const { xs, bits } = generate(seed, n);
  const t1 = freqTest(bits);
  const t2 = diffTest(bits);
  const { L, C, steps } = berlekampMassey(bits);

  // Метрики
  document.getElementById('m-n').textContent = n.toLocaleString();
  document.getElementById('m-t1').textContent = t1.toFixed(4);
  document.getElementById('m-t1-sub').innerHTML = badge(Math.abs(t1 - 0.5) < 0.05);
  document.getElementById('m-t2').textContent = t2.toFixed(4);
  document.getElementById('m-t2-sub').innerHTML = badge(Math.abs(t2 - 0.5) < 0.05);
  document.getElementById('m-L').textContent = L;
  document.getElementById('m-L-sub').innerHTML = badge(L >= n * 0.4);

  // Таблиця 20
  const tbody = document.getElementById('table-body');
  tbody.innerHTML = '';
  for (let i = 1; i <= 20; i++) {
    const tr = document.createElement('tr');
    tr.innerHTML = `<td>${i}</td><td>${xs[i-1]}</td><td>${xs[i]}</td><td>${bits[i-1]}</td>`;
    tbody.appendChild(tr);
  }

  // Біти
  let html = '';
  for (let i = 0; i < Math.min(200, n); i++) {
    if (i > 0 && i % 8 === 0) html += ' ';
    html += bits[i] ? `<span>1</span>` : '0';
  }
  document.getElementById('bits-preview').innerHTML = html;

  // Частотний тест
  const ones  = bits.reduce((a, b) => a + b, 0);
  const zeros = n - ones;
  document.getElementById('freq-details').innerHTML =
    row('Кількість одиниць', ones) +
    row('Кількість нулів', zeros) +
    row(`t₁ = ${ones} / ${n}`, `${t1.toFixed(6)} &nbsp; ${badge(Math.abs(t1 - 0.5) < 0.05)}`) +
    row('Ідеальне значення', '0.5') +
    row('Відхилення |t₁ − 0.5|', Math.abs(t1 - 0.5).toFixed(6));

  // Диференційний тест
  let changes = 0;
  for (let i = 1; i < n; i++) if (bits[i] !== bits[i-1]) changes++;
  document.getElementById('diff-details').innerHTML =
    row('Кількість змін бітів', changes) +
    row(`t₂ = ${changes} / ${n - 1}`, `${t2.toFixed(6)} &nbsp; ${badge(Math.abs(t2 - 0.5) < 0.05)}`) +
    row('Ідеальне значення', '0.5') +
    row('Відхилення |t₂ − 0.5|', Math.abs(t2 - 0.5).toFixed(6));

  // BM деталі
  let bmHtml =
    row('Лінійна складність L', L) +
    row('Ідеальне L = n/2', Math.round(n / 2)) +
    row('L / n', (L / n).toFixed(4) + ' &nbsp; ' + badge(L >= n * 0.4)) +
    row('Поліном C(D)', polyStr(C)) +
    `<div style="margin-top:12px; font-size:12px; color:#888; font-weight:600; padding-bottom:4px;">Кроки де L змінювалось або коригувався C(D):</div>`;
  for (const s of steps) {
    bmHtml += row(
      `N=${s.N}, d=${s.d} → ${s.action}, L=${s.L}`,
      `C(D) = ${s.poly}`
    );
  }
  document.getElementById('bm-details').innerHTML = bmHtml;

  // Висновок
  const t1ok = Math.abs(t1 - 0.5) < 0.05;
  const t2ok = Math.abs(t2 - 0.5) < 0.05;
  const Lok  = L >= n * 0.4;
  const all  = t1ok && t2ok && Lok;
  document.getElementById('conclusion').innerHTML = `
    <p>Конгруентний генератор з параметрами a=106, b=1283, m=6075 та початковим значенням X₀=${seed} згенерував ${n} бітів.</p>
    <br>
    <p><b>Частотний тест:</b> t₁ = ${t1.toFixed(4)} — ${t1ok ? 'відхилення від 0.5 менше 0.05, баланс нулів та одиниць задовільний.' : 'відхилення від 0.5 перевищує 0.05, баланс незадовільний.'}</p>
    <p><b>Диференційний тест:</b> t₂ = ${t2.toFixed(4)} — ${t2ok ? 'зміни між сусідніми бітами рівномірні, тест пройдено.' : 'нерівномірність змін між бітами, тест не пройдено.'}</p>
    <p><b>Лінійна складність:</b> L = ${L} при n = ${n} (ідеал ≈ ${Math.round(n/2)}) — ${Lok ? 'значення достатнє, послідовність важко передбачити.' : 'значення занадто мале, послідовність легко передбачити.'}</p>
    <p><b>Поліном C(D) = ${polyStr(C)}</b> — структура LFSR що відтворює послідовність.</p>
    <br>
    <p><b>Загальний висновок:</b> ${all ? 'Всі тести пройдено успішно. Конгруентний генератор з обраними параметрами генерує якісну псевдовипадкову послідовність.' : 'Не всі тести пройдено. Якість послідовності потребує покращення (збільш n або зміни seed).'}</p>
  `;
}

runAll();
</script>
</body>
</html>
Editor is loading...
Leave a Comment