User Tools

Site Tools


tanszek:oktatas:techcomm:encoding_integers

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
tanszek:oktatas:techcomm:encoding_integers [2026/10/12 18:25] – kneheztanszek:oktatas:techcomm:encoding_integers [2026/10/12 18:32] (current) – knehez
Line 1: Line 1:
-==== Integer representations ====+===== Integer representations =====
  
 Computers store data as bits. Each bit can have one of two values: 0 or 1. A byte consists of 8 bits, so it has 2<sup>8</sup> = 256 possible bit patterns. Computers store data as bits. Each bit can have one of two values: 0 or 1. A byte consists of 8 bits, so it has 2<sup>8</sup> = 256 possible bit patterns.
Line 11: Line 11:
 === Unsigned integers === === Unsigned integers ===
  
-In ordinary decimal notation, the positions of the digits have weights of 1, 10, 100, and so on, starting from the right.+In ordinary decimal notation, digit positions have weights of 1, 10, 100, and so on, starting from the right.
  
 In binary notation, the weights are powers of two: In binary notation, the weights are powers of two:
Line 148: Line 148:
 </code> </code>
  
-The expected result is +2. To obtain it, an arithmetic procedure for sign-magnitude numbers must take the signs into account and subtract the magnitudes.+The expected result is +2. To get it, an arithmetic procedure for sign-magnitude numbers must account for the signs and subtract the magnitudes.
  
 === Two's complement representation === === Two's complement representation ===
Line 154: Line 154:
 A widely used alternative for signed integers is **two's complement representation**. A widely used alternative for signed integers is **two's complement representation**.
  
-Its main advantage is that positive and negative integers can be added using the same binary addition procedure as unsigned integers.+Its main advantage is that you can add positive and negative integers using the same binary addition procedure as with unsigned integers.
  
 Let us first see what bit pattern would make this possible. Let us first see what bit pattern would make this possible.
Line 216: Line 216:
 | Weight | **−128** | 64 | 32 | 16 | 8 | 4 | 2 | 1 | | Weight | **−128** | 64 | 32 | 16 | 8 | 4 | 2 | 1 |
  
-Only the weight of the leftmost bit differs from the unsigned case.+Only the leftmost bit's weight differs from the unsigned case.
  
 Consequently: Consequently:
Line 278: Line 278:
 The result is correct. The result is correct.
  
-The carry-out is discarded in this fixed-width calculation. **A carry-out does not, by itself, indicate signed overflow.**+This fixed-width calculation discards the carry-out. **A carry-out does not, by itself, indicate signed overflow.**
  
 Two's complement makes addition convenient, but the result must still fit in the available signed range. Two's complement makes addition convenient, but the result must still fit in the available signed range.
Line 308: Line 308:
 **Carry-out and signed overflow describe different conditions.** **Carry-out and signed overflow describe different conditions.**
  
-These examples describe fixed-width binary arithmetic. Programming languages may handle out-of-range calculations differently, so their rules must also be checked when writing a program.+These examples describe fixed-width binary arithmetic. Programming languages may handle out-of-range calculations differently, so you must also check their rules when writing a program.
  
 === Check your understanding === === Check your understanding ===
Line 327: Line 327:
   - No. The greatest positive value is +127. The unsigned pattern for 156, 10011100, represents −100 when interpreted as two's complement.   - No. The greatest positive value is +127. The unsigned pattern for 156, 10011100, represents −100 when interpreted as two's complement.
   - The resulting pattern is **10000000**, which represents −128. The mathematical result, +128, is outside the range, so signed overflow occurs.   - The resulting pattern is **10000000**, which represents −128. The mathematical result, +128, is outside the range, so signed overflow occurs.
 +
 +<html>
 +<div class="tc-lab">
 +  <style>
 +    .tc-lab {
 +      max-width: 900px;
 +      margin: 24px auto;
 +      padding: 24px;
 +      border: 1px solid #cbd5e1;
 +      border-radius: 16px;
 +      background: #f8fafc;
 +      color: #172033;
 +      font: 16px/1.6 system-ui, sans-serif;
 +    }
 +    .tc-lab * { box-sizing: border-box; }
 +    .tc-lab h2, .tc-lab h3 { color: #172033; margin: 0 0 12px; }
 +    .tc-lab p { margin: 10px 0; }
 +    .tc-lab button, .tc-lab input { font: inherit; }
 +    .tc-lab button {
 +      padding: 8px 14px;
 +      border: 1px solid #94a3b8;
 +      border-radius: 8px;
 +      background: #fff;
 +      color: #172033;
 +      cursor: pointer;
 +    }
 +    .tc-lab button:hover { background: #e2e8f0; }
 +    .tc-lab button:focus-visible, .tc-lab input:focus-visible {
 +      outline: 3px solid #2563eb;
 +      outline-offset: 3px;
 +    }
 +    .tc-lab .tc-card {
 +      padding: 20px;
 +      margin-top: 18px;
 +      border: 1px solid #dbe3ee;
 +      border-radius: 12px;
 +      background: #fff;
 +    }
 +    .tc-lab .tc-controls {
 +      display: flex;
 +      gap: 10px;
 +      align-items: center;
 +      flex-wrap: wrap;
 +      margin: 12px 0;
 +    }
 +    .tc-lab input[type="number"] {
 +      width: 110px;
 +      padding: 7px 10px;
 +      border: 1px solid #94a3b8;
 +      border-radius: 7px;
 +      background: #fff;
 +      color: #172033;
 +    }
 +    .tc-lab input[type="range"] { width: 100%; margin: 12px 0; }
 +    .tc-lab .tc-bits {
 +      display: grid;
 +      grid-template-columns: repeat(8, minmax(0, 1fr));
 +      gap: 6px;
 +      margin: 16px 0;
 +    }
 +    .tc-lab .tc-bit-cell { text-align: center; min-width: 0; }
 +    .tc-lab .tc-bit {
 +      display: block;
 +      width: 100%;
 +      padding: 10px 0;
 +      font: bold 25px/1.2 monospace;
 +      border: 2px solid #cbd5e1;
 +      background: #f1f5f9;
 +    }
 +    .tc-lab .tc-bit[aria-pressed="true"] {
 +      background: #dbeafe;
 +      border-color: #2563eb;
 +      color: #1e40af;
 +    }
 +    .tc-lab .tc-sign .tc-bit[aria-pressed="true"] {
 +      background: #ffedd5;
 +      border-color: #c2410c;
 +      color: #9a3412;
 +    }
 +    .tc-lab .tc-weight {
 +      display: block;
 +      font-size: 13px;
 +      padding-top: 5px;
 +      color: #475569;
 +    }
 +    .tc-lab .tc-results {
 +      display: flex;
 +      flex-wrap: wrap;
 +      gap: 12px;
 +      margin: 12px 0;
 +    }
 +    .tc-lab .tc-result {
 +      flex: 1 1 180px;
 +      padding: 12px;
 +      border-radius: 8px;
 +      background: #eff6ff;
 +    }
 +    .tc-lab .tc-value { display: block; font-size: 28px; font-weight: bold; }
 +    .tc-lab .tc-mono {
 +      font-family: ui-monospace, monospace;
 +      white-space: pre-wrap;
 +      overflow-wrap: anywhere;
 +    }
 +    .tc-lab .tc-note { color: #475569; font-size: 14px; }
 +    .tc-lab .tc-feedback {
 +      margin-top: 12px;
 +      padding: 12px;
 +      border-left: 4px solid #64748b;
 +      background: #f1f5f9;
 +    }
 +    .tc-lab .tc-feedback[data-kind="success"] {
 +      border-color: #15803d;
 +      background: #f0fdf4;
 +    }
 +    .tc-lab .tc-feedback[data-kind="error"] {
 +      border-color: #b45309;
 +      background: #fffbeb;
 +    }
 +    .tc-lab .tc-primary { background: #1d4ed8; color: #fff; border-color: #1d4ed8; }
 +    .tc-lab .tc-primary:hover { background: #1e40af; }
 +    .tc-lab .tc-target { font-size: 30px; font-weight: bold; color: #1d4ed8; }
 +    .tc-lab [hidden] { display: none !important; }
 +    @media (max-width: 520px) {
 +      .tc-lab { padding: 12px; }
 +      .tc-lab .tc-card { padding: 12px; }
 +      .tc-lab .tc-bits { gap: 3px; }
 +      .tc-lab .tc-bit { font-size: 21px; }
 +      .tc-lab .tc-weight { font-size: 11px; }
 +    }
 +  </style>
 +
 +  <h2>Two's Complement: Explore and Play</h2>
 +  <p>
 +    Eight bits can represent signed integers from <strong>−128 to +127</strong>.
 +    Click the bits to see how the same pattern can have different meanings.
 +  </p>
 +
 +  <section class="tc-card">
 +    <h3>1. Explore the bits</h3>
 +    <div class="tc-controls">
 +      <label>
 +        Signed decimal value:
 +        <input data-role="number" type="number" min="-128" max="127" step="1" value="-5">
 +      </label>
 +      <button type="button" data-preset="-128">−128</button>
 +      <button type="button" data-preset="-5">−5</button>
 +      <button type="button" data-preset="-1">−1</button>
 +      <button type="button" data-preset="0">0</button>
 +      <button type="button" data-preset="127">127</button>
 +    </div>
 +
 +    <input data-role="slider" type="range" min="-128" max="127" value="-5"
 +           aria-label="Signed decimal value">
 +
 +    <div data-role="explore-bits" class="tc-bits"></div>
 +    <p class="tc-note">
 +      The weights below the bits apply to two's complement.
 +      The leftmost bit has weight <strong>−128</strong>.
 +    </p>
 +
 +    <div class="tc-results" aria-live="polite">
 +      <div class="tc-result">
 +        Two's complement value
 +        <span data-role="signed" class="tc-value"></span>
 +      </div>
 +      <div class="tc-result">
 +        Unsigned value
 +        <span data-role="unsigned" class="tc-value"></span>
 +      </div>
 +    </div>
 +
 +    <div data-role="sum" class="tc-mono"></div>
 +    <p data-role="interpretation"></p>
 +
 +    <div class="tc-controls">
 +      <button type="button" data-action="negate">Negate: invert bits and add 1</button>
 +      <button type="button" data-action="increment">Add 1</button>
 +    </div>
 +    <div data-role="operation" class="tc-feedback tc-mono"
 +         aria-live="polite">Try negating −5, or adding 1 to 127.</div>
 +  </section>
 +
 +  <section class="tc-card">
 +    <h3>2. Build the negative number</h3>
 +    <p>
 +      Set the eight bits to encode this number in two's complement:
 +      <span data-role="target" class="tc-target"></span>
 +    </p>
 +    <p>Click a bit to switch between 0 and 1. Then check your answer.</p>
 +
 +    <div data-role="game-bits" class="tc-bits"></div>
 +
 +    <div class="tc-controls">
 +      <button type="button" data-action="check" class="tc-primary">Check answer</button>
 +      <button type="button" data-action="hint">Show a hint</button>
 +      <button type="button" data-action="solution">Show solution</button>
 +      <button type="button" data-action="next">Next number</button>
 +    </div>
 +
 +    <p data-role="score" class="tc-note"></p>
 +    <div data-role="feedback" class="tc-feedback" aria-live="polite"></div>
 +    <div data-role="hint" class="tc-feedback tc-mono" hidden></div>
 +    <div data-role="solution" class="tc-feedback tc-mono" hidden></div>
 +  </section>
 +
 +  <script>
 +    (function () {
 +      "use strict";
 +
 +      const root = document.currentScript.parentElement;
 +      const find = role => root.querySelector('[data-role="' + role + '"]');
 +      const weights = [-128, 64, 32, 16, 8, 4, 2, 1];
 +
 +      let word = 251;
 +      let gameWord = 0;
 +      let target = -5;
 +      let solved = false;
 +      let revealed = false;
 +      let score = 0;
 +      let completed = 0;
 +
 +      const binary = n => (n & 255).toString(2).padStart(8, "0");
 +      const signed = n => n >= 128 ? n - 256 : n;
 +      const display = n => n < 0 ? "−" + Math.abs(n) : String(n);
 +
 +      function createBits(container, onToggle) {
 +        const buttons = [];
 +        weights.forEach((weight, index) => {
 +          const cell = document.createElement("div");
 +          cell.className = "tc-bit-cell" + (index === 0 ? " tc-sign" : "");
 +
 +          const button = document.createElement("button");
 +          button.type = "button";
 +          button.className = "tc-bit";
 +          button.textContent = "0";
 +          button.setAttribute("aria-pressed", "false");
 +          button.addEventListener("click", () => onToggle(7 - index));
 +
 +          const label = document.createElement("span");
 +          label.className = "tc-weight";
 +          label.textContent = display(weight);
 +
 +          cell.append(button, label);
 +          container.append(cell);
 +          buttons.push(button);
 +        });
 +        return buttons;
 +      }
 +
 +      function updateBits(buttons, value) {
 +        buttons.forEach((button, index) => {
 +          const bit = (value >> (7 - index)) & 1;
 +          button.textContent = bit;
 +          button.setAttribute("aria-pressed", bit ? "true" : "false");
 +          button.setAttribute(
 +            "aria-label",
 +            "Bit " + (7 - index) + ", weight " + weights[index] +
 +            ", value " + bit + ". Click to toggle."
 +          );
 +        });
 +      }
 +
 +      function feedback(element, message, kind) {
 +        element.textContent = message;
 +        element.dataset.kind = kind || "";
 +      }
 +
 +      const exploreButtons = createBits(find("explore-bits"), bit => {
 +        word ^= 1 << bit;
 +        renderExplore();
 +        feedback(find("operation"), "Bit changed. Compare the two interpretations.");
 +      });
 +
 +      const gameButtons = createBits(find("game-bits"), bit => {
 +        gameWord ^= 1 << bit;
 +        updateBits(gameButtons, gameWord);
 +        if (!solved && !revealed) {
 +          feedback(find("feedback"), "Ready? Check your answer.");
 +        }
 +      });
 +
 +      function renderExplore() {
 +        const value = signed(word);
 +        find("number").value = value;
 +        find("slider").value = value;
 +        find("signed").textContent = display(value);
 +        find("unsigned").textContent = word;
 +        updateBits(exploreButtons, word);
 +
 +        const terms = weights.filter((weight, index) => word & (1 << (7 - index)));
 +        find("sum").textContent =
 +          (terms.length ? terms.map(display).join(" + ") : "0") +
 +          " = " + display(value);
 +
 +        find("interpretation").textContent = value < 0
 +          ? "The leftmost bit is 1. Read the pattern as unsigned, then subtract 256: " +
 +            word + " − 256 = " + display(value) + "."
 +          : "The leftmost bit is 0. Unsigned and two's complement interpretations agree.";
 +      }
 +
 +      find("number").addEventListener("input", function () {
 +        const value = this.valueAsNumber;
 +        const valid = Number.isInteger(value) && value >= -128 && value <= 127;
 +        this.setAttribute("aria-invalid", valid ? "false" : "true");
 +        if (!valid) {
 +          feedback(find("operation"), "Enter an integer from −128 to 127.", "error");
 +          return;
 +        }
 +        word = value & 255;
 +        renderExplore();
 +        feedback(find("operation"), "Value updated. Try changing an individual bit.");
 +      });
 +
 +      function setValue(value) {
 +        word = value & 255;
 +        find("number").setAttribute("aria-invalid", "false");
 +        renderExplore();
 +        feedback(find("operation"), "Value updated. Try changing an individual bit.");
 +      }
 +
 +      find("slider").addEventListener("input", event => {
 +        setValue(Number(event.target.value));
 +      });
 +
 +      root.querySelectorAll("[data-preset]").forEach(button => {
 +        button.addEventListener("click", () => setValue(Number(button.dataset.preset)));
 +      });
 +
 +      root.querySelector('[data-action="negate"]').addEventListener("click", () => {
 +        const before = word;
 +        const value = signed(before);
 +        const inverted = before ^ 255;
 +        word = (inverted + 1) & 255;
 +        renderExplore();
 +
 +        let message =
 +          "Original:  " + binary(before) + "  (" + display(value) + ")\n" +
 +          "Invert:    " + binary(inverted) + "\n" +
 +          "Add 1:     " + binary(word) + "  (" + display(signed(word)) + ")";
 +
 +        if (value === -128) {
 +          message += "\nOverflow: +128 cannot be represented in 8-bit two's complement." +
 +                     "\nKeeping 8 bits leaves the pattern for −128.";
 +        } else if (value === 0) {
 +          message += "\nZero remains zero. The carry-out is discarded.";
 +        } else {
 +          message += "\nThe sign has changed; the magnitude is unchanged.";
 +        }
 +        feedback(find("operation"), message, value === -128 ? "error" : "");
 +      });
 +
 +      root.querySelector('[data-action="increment"]').addEventListener("click", () => {
 +        const before = word;
 +        const value = signed(before);
 +        const total = before + 1;
 +        word = total & 255;
 +        renderExplore();
 +
 +        let message =
 +          "  " + binary(before) + "  (" + display(value) + ")\n" +
 +          "+ 00000001  (+1)\n" +
 +          "= " + total.toString(2).padStart(8, "0") + "\n" +
 +          "Keep 8 bits: " + binary(word) + "  (" + display(signed(word)) + ")";
 +
 +        if (value === 127) {
 +          message += "\nSigned overflow: 128 is outside the range −128 to 127." +
 +                     "\nThere is no carry-out, but the signed result is out of range.";
 +        } else if (total > 255) {
 +          message += "\nThe carry-out is discarded. −1 + 1 = 0: no signed overflow.";
 +        } else {
 +          message += "\nThe result fits: no signed overflow.";
 +        }
 +        feedback(find("operation"), message, value === 127 ? "error" : "");
 +      });
 +
 +      function updateScore() {
 +        find("score").textContent =
 +          "Solved without revealing the solution: " + score +
 +          " | Completed challenges: " + completed +
 +          ". Hints are allowed.";
 +      }
 +
 +      function startChallenge(first) {
 +        const previous = target;
 +        if (!first) {
 +          do {
 +            target = -(1 + Math.floor(Math.random() * 128));
 +          } while (target === previous);
 +        }
 +
 +        gameWord = 0;
 +        solved = false;
 +        revealed = false;
 +        find("target").textContent = display(target);
 +        find("hint").hidden = true;
 +        find("solution").hidden = true;
 +        updateBits(gameButtons, gameWord);
 +        feedback(find("feedback"), "Build the bit pattern, then press Check answer.");
 +        updateScore();
 +      }
 +
 +      root.querySelector('[data-action="check"]').addEventListener("click", () => {
 +        if (signed(gameWord) === target) {
 +          if (!solved && !revealed) {
 +            score++;
 +            completed++;
 +          }
 +          solved = true;
 +          updateScore();
 +          feedback(
 +            find("feedback"),
 +            "Correct! " + binary(gameWord) + " represents " + display(target) +
 +            ". Press Next number for another challenge.",
 +            "success"
 +          );
 +        } else {
 +          feedback(
 +            find("feedback"),
 +            binary(gameWord) + " represents " + display(signed(gameWord)) +
 +            ", not " + display(target) + ". Adjust the bits and try again.",
 +            "error"
 +          );
 +        }
 +      });
 +
 +      root.querySelector('[data-action="hint"]').addEventListener("click", () => {
 +        const magnitude = Math.abs(target);
 +        find("hint").hidden = false;
 +        find("hint").textContent =
 +          "Start with the magnitude " + magnitude + ": " + binary(magnitude) +
 +          "\nInvert all eight bits, then add 1." +
 +          "\nThe answer must begin with 1 because the target is negative." +
 +          (target === -128
 +            ? "\nHere, 10000000 is the unsigned magnitude 128 used in the calculation;" +
 +              "\n+128 itself is outside the signed 8-bit range."
 +            : "");
 +      });
 +
 +      root.querySelector('[data-action="solution"]').addEventListener("click", () => {
 +        if (!solved && !revealed) completed++;
 +        revealed = true;
 +        const magnitude = Math.abs(target);
 +        const inverted = magnitude ^ 255;
 +        const answer = (inverted + 1) & 255;
 +
 +        find("solution").hidden = false;
 +        find("solution").textContent =
 +          "Magnitude: " + binary(magnitude) + "  (" + magnitude + " unsigned)\n" +
 +          "Invert:    " + binary(inverted) + "\n" +
 +          "Add 1:     " + binary(answer) + "  (" + display(target) + " signed)\n\n" +
 +          "Check: " + answer + " − 256 = " + display(target);
 +
 +        feedback(find("feedback"), "Solution shown. Press Next number when you are ready.");
 +        updateScore();
 +      });
 +
 +      root.querySelector('[data-action="next"]').addEventListener("click", () => {
 +        startChallenge(false);
 +      });
 +
 +      renderExplore();
 +      startChallenge(true);
 +    })();
 +  </script>
 +</div>
 +</html>
tanszek/oktatas/techcomm/encoding_integers.1791829544.txt.gz · Last modified: by knehez