Computer science basics: 50 cards on bits, memory and concurrency
CS fundamentals: binary and hex, two’s complement, Big-O, stack vs heap, threads and deadlocks, CPU caches, compilers, UTF-8 and floating point.
Practice now
Study without an account
1011 to decimalScheduled with the default Askesis timings. Progress is saved in this browser.
All 50 cards
- 1Convert binary
1011to decimal118 + 0 + 2 + 1: each bit is worth twice the bit to its right. - 2Hex
0xFFin decimal and in binary255, or1111 1111One hex digit is exactly four bits (a nibble), so a byte is always two hex digits. That’s why hex is used for bytes, colors and memory addresses. - 3Range of an -bit unsigned integerto , so a byte holds 0–255
- 4Negate a number in two’s complementInvert every bit, then add 15 is
0000 0101; inverting gives1111 1010; adding 1 gives1111 1011, which is −5. - 5Range of an 8-bit two’s complement integer−128 to 127; in general toTwo’s complement has a single zero, and the CPU adds and subtracts signed numbers with the same circuits as unsigned ones. That’s why every modern CPU uses it.
- 6What happens on integer overflow?The result doesn’t fit the type. With wrapping arithmetic it wraps around: 127 + 1 in an 8-bit signed integer becomes −128Languages differ: in C, signed overflow is undefined behavior (unsigned values wrap), Java wraps silently, Rust panics in debug builds, and Python integers simply grow.
- 7What do
x << kandx >> kdo to a non-negative integer?Multiply by and divide by , rounding down5 << 3is 40, and40 >> 2is 10. - 8Test whether a positive integer is a power of two
(x & (x - 1)) == 0A power of two has exactly one 1 bit. Subtracting 1 clears that bit and sets all the bits below it, so the AND is zero. - 9Big-endian vs little-endianThe byte order of multi-byte values: big-endian stores the most significant byte first, little-endian the least significant byte firstx86 and nearly all ARM systems are little-endian, so
0x12345678is stored as78 56 34 12. Network protocols use big-endian (“network byte order”). - 10What does Big-O notation describe?How an algorithm’s running time or memory grows with the input size, as an upper bound that ignores constant factors and lower-order terms
- 11Order by growth: , , , , ,
- 12Simplify: drop constant factors and keep only the fastest-growing term
- 13Time complexity of this loop?python
i = 1 while i < n: i *= 2: doubles on every pass, so the loop runs about times - 14Time–space trade-offSpending memory to save time, or the reverse: a hash set uses extra space so each lookup is instead of an scan
- 15P vs NPP: problems solvable in polynomial time. NP: problems whose solutions can be checked in polynomial time. Whether P = NP is the most famous open question in computer scienceNP-complete problems, such as SAT and the decision version of the traveling salesman problem, are the hardest in NP: a polynomial-time algorithm for any one of them would solve them all.
- 16Stack vs heapThe stack holds function call frames and local variables, freed automatically when a function returns; it’s fast but small. The heap holds dynamically allocated data that can outlive a call; it’s larger but slower to manageEach thread has its own stack, while the heap is shared by all threads of a process.
- 17What causes a stack overflow?Using more stack than its fixed limit, usually through recursion that is too deep or never stopsDefault stack sizes are typically 1–8 MB, e.g. 8 MB for the main thread on Linux and 1 MB on Windows.
- 18Memory leakMemory that stays allocated after it’s no longer needed, so usage keeps growingGarbage-collected languages leak too, through references you forgot about: ever-growing caches, global lists, event listeners that are never removed.
- 19How does a tracing garbage collector decide what to free?It frees objects that can no longer be reached from the roots: stack variables, globals and registersReference counting (used by CPython and Swift) frees an object when its count drops to zero, but can’t reclaim reference cycles on its own; CPython adds a cycle collector.
- 20Dangling pointer (use-after-free)A pointer to memory that has already been freed; reading or writing through it is undefined behavior and a classic security bug
- 21Virtual memoryEach process gets its own private address space, which the OS and the CPU’s memory management unit (MMU) map onto physical memory in fixed-size pagesPages are commonly 4 KiB. Virtual memory isolates processes from each other and lets the OS move rarely used pages to disk.
- 22Page faultAn access to a virtual page that isn’t currently in physical memory. The OS loads or allocates the page, or kills the process if the address is invalid (a segmentation fault)
- 23Process vs threadA process is a running program with its own address space and resources. Threads run inside a process and share its memory, but each has its own stack and registersThreads are cheaper to create and switch between, but a bug in one thread can corrupt memory for all of them.
- 24Context switchThe CPU saves the state (registers, program counter) of the running thread or process and restores another’sBesides the direct cost, the next thread starts with caches full of someone else’s data.
- 25Concurrency vs parallelismConcurrency is structuring a program to make progress on several tasks at once, possibly by interleaving them on one core. Parallelism is executing tasks at the same instant on multiple coresRob Pike: “Concurrency is about dealing with lots of things at once. Parallelism is about doing lots of things at once.”
- 26Why can this lose updates when two threads run it?java
// each thread runs this 1,000,000 times count++;count++is a read, an add and a write. Two threads can read the same old value and both write back that value + 1, so increments are lost. This is a race conditionFix it with a lock (synchronized) or an atomic counter (AtomicInteger.incrementAndGet()). - 27MutexA lock that lets only one thread at a time into a critical section; other threads block until it’s released
- 28Semaphore vs mutexA semaphore is a counter that lets up to N threads in at once, e.g. to share a pool of 10 connections. A mutex allows exactly one holder, and the thread that locked it must unlock it
- 29DeadlockTwo or more threads each wait for a resource another one holds, so none of them can ever proceedThread A holds lock 1 and waits for lock 2, while thread B holds lock 2 and waits for lock 1.
- 30The four Coffman conditions for deadlockMutual exclusion, hold and wait, no preemption, circular waitDeadlock needs all four at once, so breaking any one of them prevents it.
- 31Simplest practical way to prevent deadlocks between locksAlways acquire locks in the same global order, which makes circular wait impossibleTimeouts are another option:
tryLockwith a deadline gives up and retries instead of waiting forever. - 32Livelock vs starvationLivelock: threads keep reacting to each other and changing state, but none makes progress. Starvation: a thread waits indefinitely because others keep getting the resource first
- 33Atomic operationAn operation that other threads see as all or nothing; no thread can observe it half doneCompare-and-swap (CAS) is the hardware building block of lock-free code: write the new value only if the current value is still the one you expect.
- 34Why do CPUs have caches?Main memory takes about 100 ns to respond, roughly 100 times longer than the nearest cache, so small, fast caches keep recently used data close to the cores
- 35L1, L2 and L3 cachesL1 is the smallest and fastest, private to each core; L2 is larger and slower; L3 is the largest and slowest, usually shared by all cores, yet still much faster than RAMTypical sizes: tens of KB for L1, hundreds of KB to a few MB for L2, and many MB for L3.
- 36Temporal vs spatial localityTemporal: data used recently is likely to be used again soon. Spatial: data near recently used data is likely to be used soonCaches exploit spatial locality by loading whole cache lines, typically 64 bytes, rather than single bytes.
- 37Why is this loop faster in C than the same loop summing
a[j][i]?cfor (int i = 0; i < N; i++) for (int j = 0; j < N; j++) sum += a[i][j];C stores 2D arrays row by row (row-major), soa[i][j]walks memory sequentially and uses every byte of each cache line.a[j][i]jumps a whole row on each step and misses the cache far more often - 38Compiler vs interpreterA compiler translates the whole program ahead of time into machine code (or another language). An interpreter executes the program directly at runtime, from source or bytecodeReal implementations mix both: Java compiles to bytecode that the JVM interprets and JIT-compiles, and CPython compiles to bytecode that it then interprets.
- 39JIT (just-in-time) compilationCompiling frequently run (“hot”) code to machine code while the program runs, using what it observes at runtime to optimize itUsed by the JVM’s HotSpot, JavaScript engines such as V8, and .NET.
- 40Main phases of a compilerLexing (characters → tokens), parsing (tokens → syntax tree), semantic analysis (types and scopes), optimization of an intermediate representation, and code generation
- 41Static vs dynamic typingStatic: types are checked at compile time (Java, Rust, TypeScript). Dynamic: values carry their types, which are checked at runtime (Python, JavaScript, Ruby)
- 42ASCIIA 7-bit character encoding with 128 codes: English letters, digits, punctuation and control characters
Ais 65,ais 97 and0is 48. - 43Unicode vs UTF-8Unicode gives every character a number, its code point (U+0000 to U+10FFFF). UTF-8 is one way of encoding those code points as bytes
- 44How many bytes does UTF-8 use per character?1 to 4. ASCII characters take 1 byte (so ASCII text is already valid UTF-8),
étakes 2,€takes 3 and most emoji take 4 - 45Why is
"😀".length2 in JavaScript?JavaScript strings are UTF-16, andlengthcounts 16-bit code units. Characters above U+FFFF, like most emoji, need two of them (a surrogate pair)Java and the Windows APIs use UTF-16 too.[..."😀"].lengthcounts code points and gives 1. - 46Why is
0.1 + 0.2 == 0.3false?Binary floating point can’t represent 0.1 or 0.2 exactly, so the sum comes out as0.30000000000000004Just as 1/3 never ends in decimal, 1/10 is a repeating fraction in binary. - 47Layout of an IEEE 754 double (64-bit float)1 sign bit, 11 exponent bits and 52 fraction bits, giving about 15–17 significant decimal digitsA 32-bit float has 1, 8 and 23 bits (about 7 digits). Every integer up to is exact in a double, which is why JavaScript’s
Number.MAX_SAFE_INTEGERis . - 48How should you compare two floats for equality?Check whether they are within a small tolerance of each other instead of using
==pythonimport math math.isclose(0.1 + 0.2, 0.3) # True - 49Why not store money in floats?Rounding errors creep in and accumulate; store whole cents as integers or use a decimal type
- 50What is special about NaN?It means “not a number”, the result of invalid operations like
0 / 0in JavaScript, and it compares unequal to everything, including itselfTest for it withNumber.isNaN(x)ormath.isnan(x);x != xis true only whenxis NaN.
Frequently asked questions
Do I need a computer science degree to use this deck?
No. The cards assume you can read a little code and explain each concept from scratch, with short examples in C, Java and Python.
How is this different from the data structures and algorithms deck?
That deck goes deep on the complexity of specific data structures and algorithms. This one covers what sits underneath: bits, memory, processes and threads, caches, compilers and number formats.
Why does 0.1 + 0.2 not equal 0.3?
Computers store floating-point numbers in binary, where 0.1 is a repeating fraction, like 1/3 in decimal. The stored values are slightly off, and the error shows up in the sum.
More in Computer science
Morse code
Learn International Morse code: all 26 letters, the 10 digits, common punctuation and signals like SOS, each with its rhythm and a memory aid.
50 cardsDS & Algorithms
Big-O for arrays, hash maps, heaps, trees and graphs, sorting trade-offs, and the patterns behind interview problems: two pointers, sliding windows, BFS, Dijkstra and DP.
50 cardsDesign patterns
SOLID, DRY, KISS and YAGNI, plus the Gang of Four patterns used most: singleton, factory, builder, adapter, decorator, observer, strategy, command and more.
50 cardsSoftware testing
Software testing fundamentals: the test pyramid, unit, integration and E2E tests, TDD, mocks vs stubs vs fakes, coverage, mutation and property-based testing.
50 cardsAPI design
API design fundamentals: REST, HTTP methods, status codes, pagination, versioning, OAuth 2.0 and JWT, CORS, OpenAPI, GraphQL, gRPC and webhooks.
50 cardsSystem design
System design fundamentals: load balancers, caching, CDNs, replication and sharding, CAP, consistency, queues, rate limiting and back-of-the-envelope math.
50 cardsCryptography
Cryptography flashcards: AES modes, RSA, elliptic curves, Diffie–Hellman, hashing, HMAC, signatures, password hashing, TLS 1.3 and common pitfalls.
50 cards