Bits, bytes, binary and hexadecimal explained simply, why integers have limits, and why decimal fractions like 0.1 are stored approximately, with a practical rule for money.
Sooner or later every programmer meets a number that "does the wrong thing": a total that is off by a tiny amount, a counter that suddenly goes negative, a colour written as #FF8800. All of these come from one fact: a computer stores numbers in a fixed number of binary digits. Knowing that one fact turns these from mysteries into things you can predict.
How binary and hexadecimal work, why whole numbers have a largest value, why 0.1 + 0.2 is not exactly 0.3, and one practical rule for storing money.
A bit is a 0 or a 1, because a circuit can be off or on. A group of 8 bits is a byte. Binary counting works like decimal, but with two digits instead of ten. Each position is worth double the one to its right: 1, 2, 4, 8, 16, 32, 64, 128. So 1101 means 8 + 4 + 0 + 1 = 13. Eight bits can make 256 different patterns, the numbers 0 to 255.
Long strings of 0s and 1s are hard to read. Hexadecimal (base 16) uses the digits 0 to 9 and then A to F for 10 to 15. One hex digit stands for exactly four bits, so one byte is always two hex digits. FF is 15 × 16 + 15 = 255, the largest byte. That is why web colours look like #FF8800: three bytes, one each for red, green and blue.
A whole number is stored in a fixed number of bits. With 8 bits you can store 0 to 255, or if negatives are allowed, -128 to 127. Add 1 to the largest value and it overflows: it wraps around, or the program stops, depending on the language. Common sizes are 8, 16, 32 and 64 bits. A 32-bit signed integer tops out at 2,147,483,647, which has surprised many systems that counted something for long enough. Some languages, such as Python, quietly switch to bigger storage when needed, but many do not.
Numbers with a fractional part are usually stored as floating point, a binary version of scientific notation. The catch is that binary can only write fractions whose denominator is a power of 2 exactly, such as 0.5 or 0.25. In decimal, 1/3 is 0.3333... forever and can never be written exactly. In the same way, 0.1 is a repeating pattern in binary and is cut off at some point. Add 0.1 and 0.2 and the tiny errors show up:
>>> 0.1 + 0.2
0.30000000000000004
>>> 0.1 + 0.2 == 0.3
False
This is not a bug in Python or JavaScript. It is how floating point works in nearly every language. The error is tiny, but an == comparison does not forgive tiny errors.
In Python, bin(13) gives '0b1101' and hex(255) gives '0xff'. Try bin(255), then int("1010", 2), then 0.1 + 0.2, then round(0.1 + 0.2, 2) == 0.3. Finally, work out by hand: what does 1010 in binary equal, and what is 3F in decimal? (10, and 3 × 16 + 15 = 63.)
If the idea of a variable as a box with a fixed size feels new, read Your First Program: Understanding Before Memorizing. For where this fits in the bigger picture, read What Computer Science Actually Is.
An honest picture of what a computer science degree really is before you start — problem-solving over memorization, why it's not just 'learning to code', and how to set the right expectations for four years.
Why memorizing syntax is the slow road and understanding what each line does is the fast one — how to read your first programs so the knowledge sticks.