Data Representation — Bits, Two's Complement & IEEE 754

কম্পিউটার আসলে সংখ্যা ও অক্ষর কীভাবে রাখে

~40 min Intermediate 10 practice problems Live code

1. Everything Is Bits

At the deepest level, a computer stores only two things — a low voltage (0) and a high voltage (1). A single 0 or 1 is a bit. Eight bits make a byte. That is all. Every number, letter, image, and song is ultimately a pattern of bits.

সবচেয়ে গভীর স্তরে কম্পিউটারে শুধু দুটি জিনিস থাকে — কম ভোল্টেজ (0) এবং বেশি ভোল্টেজ (1)। একটি 0 বা 1-কে বলা হয় bit। আট বিট মিলে হয় এক byte। যে-কোনো সংখ্যা, অক্ষর, ছবি কিংবা গান — সবকিছু শেষ পর্যন্ত বিটের একটি প্যাটার্ন।

2. Number Systems

BaseDigitsExampleC literal
Decimal (10)0–94242
Binary (2)0–11010100b101010 (GCC ext.)
Octal (8)0–752052
Hexadecimal (16)0–9, A–F2A0x2A
Decimal → Binary (conversion)

2 দিয়ে ভাগ করে ধারাবাহিকভাবে remainder নিচে থেকে উপরে পড়ুন:

42 / 2 = 21 r 0
21 / 2 = 10 r 1
10 / 2 =  5 r 0
 5 / 2 =  2 r 1
 2 / 2 =  1 r 0
 1 / 2 =  0 r 1
→  42 = 101010 (binary)

Run the conversion live — type any number in the code and press Run:

to_binary.c
#include <stdio.h>

void print_binary(unsigned int n) {
    char buf[33]; int i = 0;
    if (n == 0) { printf("0\n"); return; }
    while (n) { buf[i++] = (n & 1) ? '1' : '0'; n >>= 1; }
    while (i--) putchar(buf[i]);
    putchar('\n');
}

int main(void) {
    print_binary(42);       // → 101010
    print_binary(255);      // → 11111111
    print_binary(1024);     // → 10000000000
    return 0;
}

3. Why Hex? — One Nibble at a Time

One hex digit equals exactly 4 bits (a nibble). So 32 bits become just 8 hex digits. That is why system programmers live in hex.

1111 1010 0101 0011 F A 5 3 Figure 5.1 — Binary 1111 1010 0101 0011 = Hex 0xFA53।
বাইনারি পড়া কষ্টসাধ্য বলেই hexadecimal ব্যবহার হয়। এক হেক্স ডিজিট ঠিক ৪ বিট — তাই ৩২ বিট মানে মাত্র ৮টি হেক্স ডিজিট।

4. Unsigned vs Signed Integers

With 8 bits you get 256 patterns (2⁸). The question is — how do we interpret them?

Unsigned (uint8_t)

Range: 0 to 255

All 8 bits store the value.

0000 0000 = 0
1111 1111 = 255

Signed (int8_t)

Range: −128 to +127

Uses two's complement for negatives.

0000 0000 = 0
1111 1111 = −1
1000 0000 = −128

5. Two's Complement — How Negatives Work

Two's complement is brilliant: subtraction becomes addition. A single circuit handles both, and there is only one zero.

Rule to negate in two's complement (1) Flip every bit. (2) Add 1.
(১) প্রতিটি bit উল্টে দিন। (২) শেষে 1 যোগ করুন।
+5      = 0000 0101
Flip    = 1111 1010
Add 1   = 1111 1011    // this is −5

Check:    0000 0101
        + 1111 1011
        ----------
        1 0000 0000    // 9th bit discarded → result = 0  ✓

Verify it live in C:

twos_comp.c
#include <stdio.h>

int main(void) {
    int x = 5;
    printf("-x      = %d\n", -x);
    printf("~x + 1  = %d\n", ~x + 1);   // same result
    return 0;
}
Two's complement ব্যবহারের কারণে কম্পিউটারের hardware এক কন্ট্রোল সার্কিট দিয়েই যোগ ও বিয়োগ দুটোই করতে পারে। এ কারণে মাত্র একটিই zero থাকে — negative zero বলে আলাদা কিছু নেই।

6. The INT_MIN Surprise

Fact that shocks beginners For a 32-bit signed int, INT_MIN = −2,147,483,648, but −INT_MIN is also INT_MIN! The positive equivalent doesn't fit.

৩২-বিট signed int-এর negative range পজিটিভ range-এর চেয়ে এক ধাপ বড়। তাই INT_MIN-এর পজিটিভ সমতুল্য ৩২ বিটে আঁটে না। -INT_MIN overflow করে এবং এটি undefined behavior।
int_min.c
#include <stdio.h>
#include <limits.h>

int main(void) {
    printf("INT_MIN  = %d\n", INT_MIN);
    printf("INT_MAX  = %d\n", INT_MAX);
    return 0;
}

7. Floating Point — IEEE 754

Integers cannot store 3.14. Floats do — but through a clever trick. A float is 32 bits arranged as:

S 1 bit Exponent 8 bits Mantissa (fraction) 23 bits value = (−1)^S × 1.Mantissa × 2^(Exp − 127) Figure 5.2 — IEEE 754 single-precision float layout (32 bits)।
Float আসলে বৈজ্ঞানিক নোটেশনের binary সংস্করণ — একটি sign bit, একটি exponent এবং একটি mantissa (fraction) দিয়ে গঠিত।
The famous surprise 0.1 + 0.2 != 0.3 in IEEE 754! এটি বাগ নয় — সীমিত bit-এ দশমিক দশমিক সংখ্যার approximation রাখার মূল্য।
float_trap.c
#include <stdio.h>
#include <math.h>

int main(void) {
    double a = 0.1 + 0.2;
    double b = 0.3;

    printf("0.1 + 0.2      = %.20f\n", a);
    printf("0.3            = %.20f\n", b);
    printf("Equal?         = %s\n", a == b ? "yes" : "no");
    printf("Close enough?  = %s\n", fabs(a - b) < 1e-9 ? "yes" : "no");
    return 0;
}

Rule: never compare floats with ==. Use fabs(a - b) < 1e-9 instead.

8. Characters and ASCII

A char in C is simply a tiny integer. The ASCII standard maps 0–127 to characters: 'A' = 65, 'a' = 97, '0' = 48.

C-তে char আসলে একটি ছোট integer। ASCII টেবিল প্রতিটি character-কে একটি সংখ্যা দিয়ে চিহ্নিত করে — যেমন 'A'-র মান 65, '0'-র মান 48।
ascii.c
#include <stdio.h>

int main(void) {
    char c = 'A';
    printf("%c = %d\n", c, c);       // A = 65
    printf("%c = %d\n", c + 1, c + 1); // B = 66

    // Trick: digit char → int value
    char d = '7';
    printf("digit '%c' as int = %d\n", d, d - '0');
    return 0;
}

9. Endianness — Byte Order

An int is 4 bytes. But in what order are those bytes stored in memory?

Little-Endian

Least significant byte first. x86, x86-64, ARM (default).

0x12345678 →
78 56 34 12

Big-Endian

Most significant byte first. Network byte order.

0x12345678 →
12 34 56 78
endianness.c
#include <stdio.h>

int main(void) {
    int n = 1;
    if (*(char *)&n == 1) printf("Little-endian\n");
    else                     printf("Big-endian\n");
    return 0;
}

10. Practice Problems

  1. Convert 173 to binary and hex by hand. Then verify with code.
    ১৭৩-কে হাতে বাইনারি ও হেক্স-এ রূপান্তর করুন, তারপর কোড দিয়ে যাচাই করুন।
    ✨ Show Answer

    Binary: 10101101. Hex: 0xAD.

    convert173.c
    #include <stdio.h>
    int main(void) {
        int n = 173;
        printf("decimal = %d\n", n);
        printf("hex     = %X\n", n);
        printf("octal   = %o\n", n);
        return 0;
    }
  2. What's the decimal value of 0xDEADBEEF? What about only the last byte (0xEF)?
    0xDEADBEEF-এর দশমিক মান কত? শুধু শেষ বাইট (0xEF)-এর মান কত?
    ✨ Show Answer

    0xDEADBEEF = 3,735,928,559 (decimal). 0xEF = 239.

    deadbeef.c
    #include <stdio.h>
    int main(void) {
        unsigned int x = 0xDEADBEEF;
        printf("0xDEADBEEF = %u\n", x);
        printf("last byte  = %u\n", x & 0xFF);
        return 0;
    }
  3. Write the 8-bit two's-complement representation of −42.
    ৮-বিট two's complement-এ −42-কে লিখুন।
    ✨ Show Answer

    +42 = 00101010. Flip all bits → 11010101. Add 1 → 11010110. So −42 = 11010110.

  4. Print the sizeof of every primitive type on your machine.
    আপনার মেশিনে সব primitive type-এর sizeof প্রিন্ট করুন।
    ✨ Show Answer
    sizeof.c
    #include <stdio.h>
    int main(void) {
        printf("char        : %zu\n", sizeof(char));
        printf("short       : %zu\n", sizeof(short));
        printf("int         : %zu\n", sizeof(int));
        printf("long        : %zu\n", sizeof(long));
        printf("long long   : %zu\n", sizeof(long long));
        printf("float       : %zu\n", sizeof(float));
        printf("double      : %zu\n", sizeof(double));
        return 0;
    }
  5. Write int popcount(unsigned x) that counts the set bits — without any library.
    library ছাড়াই একটি popcount ফাংশন লিখুন, যা একটি unsigned int-এ কয়টি bit 1 সেটা গুনবে।
    ✨ Show Answer
    popcount.c
    #include <stdio.h>
    
    int popcount(unsigned int x) {
        int c = 0;
        while (x) { c += x & 1; x >>= 1; }
        return c;
    }
    
    int main(void) {
        printf("popcount(0) = %d\n", popcount(0));
        printf("popcount(7) = %d\n", popcount(7));        // 0b111 → 3
        printf("popcount(255) = %d\n", popcount(255));
        return 0;
    }
  6. Predict the output of printf("%.20f", 0.1);, then run it.
    printf("%.20f", 0.1);-এর output অনুমান করুন, তারপর চালিয়ে দেখুন।
    ✨ Show Answer

    0.1 binary-তে infinite repeating, তাই 20 decimal place-এ কিছু আনুমানিক সংখ্যা দেখা যাবে (উদাহরণ: 0.10000000000000000555)।

    point_one.c
    #include <stdio.h>
    int main(void) {
        printf("%.20f\n", 0.1);
        return 0;
    }
  7. Given unsigned char b = 200;, what is (char)b on a typical system? Explain.
    unsigned char b = 200; দেওয়া থাকলে (char)b-এর মান সাধারণ সিস্টেমে কত হবে? ব্যাখ্যা করুন।
    ✨ Show Answer

    সাধারণ সিস্টেমে char signed হয় এবং 200-এর bit pattern 11001000, যা signed 8-bit-এ −56 বোঝায়। তাই (char)200 = −56। যাচাই করুন:

    byte_cast.c
    #include <stdio.h>
    int main(void) {
        unsigned char b = 200;
        printf("unsigned = %u\n", b);
        printf("signed   = %d\n", (signed char)b);
        return 0;
    }
  8. Read a character and print its hex and binary representation.
    একটি character নিন এবং তার hex ও binary প্রতিনিধিত্ব প্রিন্ট করুন।
    ✨ Show Answer
    char_bin.c — stdin: Z
    #include <stdio.h>
    
    void print_bits(unsigned char c) {
        for (int i = 7; i >= 0; i--) putchar((c >> i) & 1 ? '1' : '0');
        putchar('\n');
    }
    
    int main(void) {
        int c = getchar();
        printf("char = %c\n", c);
        printf("dec  = %d\n", c);
        printf("hex  = 0x%02X\n", c);
        printf("bin  = "); print_bits((unsigned char)c);
        return 0;
    }
  9. Why is if (0.1 + 0.2 == 0.3) false? How should you compare floats?
    if (0.1 + 0.2 == 0.3) কেন false? কীভাবে float compare করা উচিত?
    ✨ Show Answer

    কেন false: 0.1, 0.2, 0.3 — কেউই binary-তে পুরোপুরি প্রকাশ করা যায় না। যোগফল 0.3000000000000000444... আর 0.3 নিজে 0.2999999999999999888..., তাই তারা সমান নয়।

    সঠিক উপায়: fabs(a - b) < eps — যেখানে eps একটি ছোট সংখ্যা (যেমন 1e-9)।

  10. Detect endianness without using pointers — use a union.
    Pointer ছাড়া endianness detect করুন — union ব্যবহার করে।
    ✨ Show Answer
    endian_union.c
    #include <stdio.h>
    
    int main(void) {
        union { int i; char c[sizeof(int)]; } u;
        u.i = 1;
        printf("%s\n", u.c[0] == 1 ? "Little-endian" : "Big-endian");
        return 0;
    }

Glossary (শব্দকোষ)

TermMeaningবাংলায়
BitThe smallest unit of data — a single 0 or 1.সবচেয়ে ছোট data unit — একটি 0 বা 1।
Byte8 bits grouped together.৮টি bit মিলে এক byte।
BinaryBase-2 number system using only 0 and 1.শুধু 0 এবং 1 ব্যবহার করা base-2 সংখ্যা পদ্ধতি।
HexadecimalBase-16 (0–9, A–F) — compact way to write binary.Base-16 — binary সংক্ষেপে লেখার পদ্ধতি।
Two's ComplementThe way C stores negative integers.C-তে negative integer সংরক্ষণের পদ্ধতি।
Sign BitThe leftmost bit indicating positive (0) or negative (1).সবচেয়ে বাঁদিকের bit যা চিহ্ন নির্দেশ করে।
OverflowWhen a value exceeds its type's maximum range.Type-এর সর্বোচ্চ সীমা ছাড়িয়ে যাওয়া।
IEEE 754The standard for floating-point representation.Floating-point সংখ্যা সংরক্ষণের আন্তর্জাতিক মানক।
MantissaThe significant-digit part of a floating-point number.Float-এর গুরুত্বপূর্ণ অঙ্কের অংশ।
ExponentThe power-of-two factor in IEEE 754.IEEE 754-এ ২-এর সূচক অংশ।
EndiannessThe order in which bytes of a multi-byte value are stored.একাধিক byte-এর সংখ্যা মেমরিতে কোন ক্রমে সংরক্ষিত হয়।
ASCIIA 7-bit code mapping characters to integers (e.g., 'A' = 65).Character-কে integer-এ রূপান্তরের ৭-bit কোড।
Bitwise OperationAn operation on individual bits (&, |, ^, ~, <<, >>).স্বতন্ত্র bit-এর উপর সম্পাদিত operation।

Summary — Module 05

Computers see only bits. Binary is native, hex is convenient. Integers use two's complement, giving one zero and letting one circuit do both addition and subtraction. Floats follow IEEE 754 — fast but lossy. Characters are tiny integers (ASCII). Endianness decides byte order.

কম্পিউটারের কাছে সবকিছুই bit। Binary হলো স্বাভাবিক ভাষা, hex সুবিধাজনক। Integer-এ two's complement ব্যবহার হয় বলে একটিই zero থাকে এবং একই circuit দিয়ে addition ও subtraction করা যায়। Float IEEE 754 অনুসরণ করে — দ্রুত কিন্তু approximate। Character আসলে ছোট integer (ASCII)। Endianness নির্ধারণ করে byte গুলোর সংরক্ষণের ক্রম।

Next Module → Variables, types and the C type system।