computer-science6 min read

Computer Fundamentals Tutorial: Learn Basics from Scratch (2026)

Computer Fundamentals Tutorial: Learn Basics from Scratch (2026)

Published:  |  Category: Computer Science  |  Reading time: ~15 min
Computer Fundamentals Tutorial: Learn Basics from Scratch (2026)

Computer fundamentals provide the foundational knowledge required for every other topic in computer science. From the binary number system that underpins all digital logic to the Von Neumann architecture that defines modern computer organization, this tutorial establishes the core concepts that reappear throughout the discipline. I have found that a solid grasp of fundamentals makes advanced topics — operating systems, compilers, networks — far more approachable.

We will cover number systems, Boolean algebra, computer architecture, memory hierarchy, peripheral devices, software classification, and the representation of data in memory. Each concept is connected to practical implications: why hexadecimal is convenient for debugging, how the memory hierarchy affects algorithm design, and what really happens when you double-click an executable.

Number Systems: Binary, Octal, Decimal, Hexadecimal

Computers operate in base-2 (binary), but humans find binary notation tedious for large values. Octal (base-8) and hexadecimal (base-16) are compact representations where each digit maps to a group of bits — 3 bits per octal digit, 4 bits per hex digit. Converting between bases is fundamental: divide by the target base repeatedly, collecting remainders. Two's complement is the standard way to represent signed integers: the most significant bit acts as the sign bit, and subtraction is performed by adding the two's complement.

def to_binary(n):
    if n == 0:
        return "0"
    bits = []
    while n > 0:
        bits.append(str(n % 2))
        n //= 2
    return ''.join(reversed(bits))

def to_hex(n):
    hex_chars = "0123456789ABCDEF"
    if n == 0:
        return "0"
    digits = []
    while n > 0:
        digits.append(hex_chars[n % 16])
        n //= 16
    return ''.join(reversed(digits))

def twos_complement(val, bits):
    if val >= 0:
        return format(val, f'0{bits}b')
    return format((1 << bits) + val, f'0{bits}b')

Boolean Algebra and Logic Gates

Boolean algebra defines operations on binary values: AND (both true), OR (at least one true), NOT (inversion), NAND, NOR, XOR (differing values). Logic gates are electronic implementations of these operations, forming the building blocks of digital circuits. Any Boolean function can be expressed using only NAND or NOR gates (universal gates). Truth tables enumerate outputs for all input combinations. Karnaugh maps simplify Boolean expressions by grouping adjacent 1s, minimizing the number of gates required.

class Gate:
    @staticmethod
    def AND(a, b): return a & b
    @staticmethod
    def OR(a, b): return a | b
    @staticmethod
    def NOT(a): return 1 - a
    @staticmethod
    def XOR(a, b): return a ^ b
    @staticmethod
    def NAND(a, b): return 1 - (a & b)

def half_adder(a, b):
    sum = Gate.XOR(a, b)
    carry = Gate.AND(a, b)
    return sum, carry

def full_adder(a, b, carry_in):
    s1, c1 = half_adder(a, b)
    sum, c2 = half_adder(s1, carry_in)
    carry_out = Gate.OR(c1, c2)
    return sum, carry_out

Von Neumann Architecture

The Von Neumann architecture consists of four main components: the Central Processing Unit (CPU — containing the Arithmetic Logic Unit and Control Unit), Memory (RAM), Input/Output devices, and the system bus connecting them. The stored-program concept — instructions and data share the same memory space — is the defining feature. The fetch-decode-execute cycle drives computation: the CPU fetches an instruction from memory using the Program Counter (PC), decodes it via the Control Unit, and executes it using the ALU or memory access. Harvard architecture separates instruction and data memory for performance.

# Fetch-decode-execute simulation

class CPU:
    def __init__(self, memory):
        self.registers = [0] * 16
        self.pc = 0
        self.memory = memory

    def step(self):
        instr = self.memory[self.pc]
        self.pc += 1
        op = (instr >> 12) & 0xF
        r1 = (instr >> 8) & 0xF
        r2 = (instr >> 4) & 0xF
        r3 = instr & 0xF
        if op == 0:
            self.registers[r1] = self.registers[r2] + self.registers[r3]
        elif op == 1:
            self.registers[r1] = instr & 0xFF
        print(f"PC={self.pc-1}: R{r1}={self.registers[r1]}")

Memory Hierarchy

The memory hierarchy exploits locality of reference to bridge the speed gap between fast CPUs and slow storage. Registers are fastest and smallest (bytes). Cache (L1/L2/L3) provides nanoseconds access and uses SRAM. Main memory (DRAM) provides gigabytes at microseconds latency. SSDs and HDDs provide terabytes at milliseconds. Temporal locality (accessing the same data again soon) and spatial locality (accessing nearby data) guide prefetching and cache replacement. Understanding cache lines (typically 64 bytes) is crucial for writing high-performance code.

# Cache-friendly vs cache-unsafe matrix traversal

matrix = [[0] * 1024 for _ in range(1024)]

# Row-major (fast) — exploits spatial locality
for i in range(1024):
    for j in range(1024):
        matrix[i][j] = 1

# Column-major (slow) — each access is a different row
# Every iteration jumps to a different row = cache miss per access
for j in range(1024):
    for i in range(1024):
        matrix[i][j] = 1

Data Representation: Characters, Integers, Floats

ASCII encodes characters as 7-bit values (0-127), extended to 8 bits for extended ASCII. Unicode provides a universal character set with UTF-8 encoding that is backward-compatible with ASCII and variable-length (1-4 bytes per codepoint). Floating-point numbers follow IEEE 754: a 32-bit float has 1 sign bit, 8 exponent bits (biased by 127), and 23 mantissa bits. The double-precision format uses 11 exponent bits (bias 1023) and 52 mantissa bits. Understanding floating-point representation explains why 0.1 + 0.2 != 0.3 exactly.

import struct

def float_to_bits(f):
    bits = struct.unpack('I', struct.pack('f', f))[0]
    sign = (bits >> 31) & 1
    exponent = (bits >> 23) & 0xFF
    mantissa = bits & 0x7FFFFF
    return f"{sign}:{exponent:08b}:{mantissa:023b}"

# float_to_bits(-3.75) -> "1:10000000:11100000000000000000000"
# sign=1 (negative), exponent=128 (bias 127 -> 1), mantissa=1.111 = 1.875
# value = -1 * 1.875 * 2^1 = -3.75

Software Classification and Operating Systems

Software is categorized as system software (operating system, drivers, utilities) or application software (word processors, browsers, databases). The operating system is the most critical system software — it manages resources (CPU, memory, I/O), provides a user interface, and enforces security and access control. Booting is the process of loading the OS into memory: firmware (BIOS/UEFI) performs POST and identifies a boot device, the bootloader loads the OS kernel from disk, and the kernel initializes subsystems and starts the init process.

# Simplified boot process

def boot(disk):
    firmware = BIOS()
    firmware.power_on_self_test()
    boot_device = firmware.find_boot_device()
    bootsector = disk.read_sector(boot_device, 0)
    bootloader = Bootloader(bootsector)
    kernel = bootloader.load_kernel()
    kernel.init_mmu()
    kernel.init_scheduler()
    kernel.init_filesystems()
    kernel.init_drivers()
    kernel.start_init_process()
    print("System ready")

Frequently Asked Questions

Why do computers use binary instead of decimal?

Binary requires only two voltage levels (high/low), making circuit design simpler, more reliable, and less power-hungry. Transistors naturally operate in cutoff (0) or saturation (1) modes. Decimal would require ten distinguishable voltage levels, increasing noise sensitivity and complexity.

What is the difference between RAM and ROM?

RAM (Random Access Memory) is volatile — data is lost when power is off. It is used for working memory. ROM (Read-Only Memory) is non-volatile and stores firmware (BIOS/UEFI). Modern systems use flash memory (EEPROM) for firmware updates.

How does a CPU execute an instruction?

The CPU fetches the instruction from memory at the address in the Program Counter, decodes it to determine the operation and operands, executes it (e.g., ALU operation, memory load/store, jump), and writes back the result. The PC increments (or is set by jumps) for the next cycle.

What is the difference between a process and a program?

A program is a static file on disk containing instructions. A process is a dynamic instance of a running program with its own address space, state, and resources. One program can have multiple processes (e.g., opening several browser windows).

Originally published on Ayodhyyya. Last updated June 1, 2026.