Read the magic numbers in code
& 0xFF, >>> 24, | (1 << 3), 0o644 — after lessons 11–15 you can see at a glance which bits each of these takes or sets.
Guide
Binary and Bit Operations is a 17-lesson interactive course that turns “binary” from an abstract idea into switches you can touch: type a number and its binary, octal, decimal and hexadecimal forms change together; flip a bit on or off and the value updates at once; run AND, OR, XOR or a shift on two numbers and see the result aligned bit by bit; type a fraction and watch it split into sign, exponent and mantissa fields and find out which decimal fraction it is exactly equal to in double precision. Each lesson has one concrete goal — convert a number, build 200, write the two's complement of −5, work out 5 << 3 — and the checker responds immediately.
Updated 2026-09-094 sources15 min read
Binary and Bit Operations is a 17-lesson interactive course that turns “binary” from an abstract idea into switches you can touch: type a number and its binary, octal, decimal and hexadecimal forms change together; flip a bit on or off and the value updates at once; run AND, OR, XOR or a shift on two numbers and see the result aligned bit by bit; type a fraction and watch it split into sign, exponent and mantissa fields and find out which decimal fraction it is exactly equal to in double precision. Each lesson has one concrete goal — convert a number, build 200, write the two's complement of −5, work out 5 << 3 — and the checker responds immediately.
The course has four parts: base conversion (binary ↔ decimal, powers of two, and why hexadecimal and octal are “shorthand”); signed numbers (how two's complement turns subtraction into addition, and why overflow makes 127 + 1 become −128); bit operations (AND as a mask, OR to set bits, XOR to flip them, shifts to multiply and divide, and their direct use in Linux permission bits like 755); and floating point (the IEEE 754 field layout, and the real reason 0.1 + 0.2 !== 0.3).
It takes about 45 minutes. It is for people starting to program, developers preparing for interviews, and anyone who has to look up 0x1F, & 0xFF or chmod 644 every time. No mathematics background is needed — addition is enough.
0x.?lesson=n jumps straight to a lesson.The course itself is above this page: change a value, click bit switches, fill in an answer.
Lesson 9, “find the two's complement”, asks for the 8-bit two's complement of −5:
Lesson 16, “IEEE 754 fields”, takes 0.15625 and the panel shows:
Absolute value 5 0 0 0 0 0 1 0 1
Bitwise NOT 1 1 1 1 1 0 1 0
Add one 1 1 1 1 1 0 1 1 ← answer 11111011
Check unsigned 251, signed 251 − 256 = −5 ✓0.15625 = 0.00101₂ = 1.01₂ × 2⁻³
Sign 0
Exponent −3 + 127 = 124 = 01111100 ← answer 124
Mantissa 01000000000000000000000 (implicit leading 1)
32-bit 0 01111100 01000000000000000000000 = 0x3E200000Every base is “a sum of place values”. Decimal 203 = 2×100 + 0×10 + 3×1; binary 1011 = 1×8 + 0×4 + 1×2 + 1×1 = 11. From right to left the place values are 1, 2, 4, 8, 16, 32, 64, 128 and so on. Binary to decimal means adding up the place values of the 1 bits; decimal to binary means repeatedly dividing by 2 and recording the remainders, or greedily subtracting powers of two from the largest down (the bit switches in lesson 7 visualise exactly that).
, only 2.4% away from 1000, which is why KB was used for 1024 bytes early on. That is the source of the confusion that persists today: drive manufacturers label 1 GB as bytes while operating systems compute with , so a 500 GB disk shows 465 GiB. The IEC defined KiB, MiB and GiB (binary prefixes) for this, and Linux and macOS have largely adopted them, while Windows still prints GB but computes in GiB. Worth remembering: , , , .
Binary is too long for people to read. Hexadecimal (0–9 plus A–F) uses one symbol for 4 bits, so a byte is exactly two symbols: 11111111 = FF, 10110110 = B6. The conversion does not go through decimal — split the binary into groups of 4 from the right and look each group up, which is what lesson 5 practises. Octal uses one symbol for 3 bits, historically for machines with 12-, 24- and 36-bit words, and today it lives mainly in Linux permissions (755) and C's \012 escapes. The prefixes in code are 0x for hexadecimal, 0o for octal and 0b for binary.
Every non-negative integer has exactly one binary spelling, so an 8-bit number can serve as eight independent switches (flag bits): flags = READ | WRITE, if (flags & EXEC). CSS font-weight, Unix file permissions and the flag fields in network protocol headers are all packed this way. Lesson 7 asks you to build 200 with the switches only — greedily from the top: 200 ≥ 128 so switch it on, 72 left ≥ 64 so switch it on, 8 left = 2³ so switch that one, giving 11001000.
How are negative numbers stored? The intuitive answer is to give one bit to the sign, but then there are two zeros, “+0” and “−0”, and the adder has to handle cases. Two's complement says: a leading 1 means negative, and the value equals the unsigned value minus . In 8 bits 11111111 is 255 and also 255 − 256 = −1; 10000000 is −128. To find the two's complement of a negative number: write the absolute value, invert every bit, add one — for −5 that is 00000101 → 11111010 → 11111011.
The elegance of two's complement is that addition does not need to know the signs: −5 + 5 = 11111011 + 00000101 = 1 00000000, and once the carry out of the 9th bit is discarded the result is exactly 0. Subtraction therefore becomes “add the complement”, and the CPU needs only one adder. The 8-bit two's complement range is −128 to 127: one more negative than positive, because 0 takes a place on the positive side.
The bit width is finite, so going past the end wraps around. In int8, 127 = 01111111; add one and you get 10000000, which reads as −128 in two's complement. Integer overflow in C, Java and Go happens silently like this; JavaScript's ordinary Number is a float so it does not overflow, but Int8Array, |0 and every bit operation run on 32-bit two's complement, and (2 ** 31) | 0 gives −2147483648. The famous year 2038 problem is a 32-bit signed second count overflowing to negative at 2038-01-19 03:14:07 UTC; the “score went negative” and “coins reset to zero” bugs in old games are the same thing.
The three bitwise logical operations each have established uses:
| Operation | Rule | Idiom |
|---|---|---|
AND & |
1 only when both bits are 1 | Masking: x & 0x0F takes the low 4 bits; IP & subnet mask gives the network address; n & 1 tests odd or even |
OR | |
1 when either bit is 1 | Setting bits: flags | READ turns one flag on without touching the others |
XOR ^ |
1 only when the bits differ | Flipping / undoing: x ^ m ^ m = x; one-time pads, checksums, swapping without a temporary |
Clearing a bit is AND combined with NOT: flags & ~FLAG. The two identities and are the root of every use: a ^= b; b ^= a; a ^= b swaps two numbers, and finding the single value that appears an odd number of times in an array is just XOR-ing everything together.
Shifting left by n multiplies by (filling the low bits with 0) and shifting right by n divides by , rounding down. 5 << 3 = 101000 = 40. Shifting is the cheapest multiply and divide, but its more common use is packing small fields into one integer: (r << 16) | (g << 8) | b combines three 0–255 values into a 24-bit colour, and (rgb >> 8) & 0xFF takes the G back out. Note that there are two right shifts: arithmetic >> keeps the sign bit (a negative stays negative) and logical >>> fills with 0. JavaScript shifts happen on 32 bits, so 1 << 31 gives −2147483648 and 1 << 32 equals 1 << 0 = 1, because the shift count is taken modulo 32.
Linux file permissions are nine bits: three each for owner, group and others, in the order read r = 4, write w = 2, execute x = 1. The sum of each triplet is one octal digit: rwxr-xr-x = 7, 5, 5 → 755; rw-r--r-- = 644. This is the most direct everyday use of place values and masks: chmod u+x is OR-ing in 0o100 and chmod o-w is AND-ing with ~0o002. There can also be bits 10–12 (setuid, setgid, sticky), which is why you sometimes see a four-digit 4755.
A float is scientific notation in binary:
Single precision is 32 bits = 1 sign bit s + 8 exponent bits e (bias 127) + 23 mantissa bits f; double precision is 1 + 11 (bias 1023) + 52. The mantissa stores only the fractional part — the leading 1 of the integer part is implicit, which buys an extra bit of precision for free. The exponent is stored with a bias so that comparing floats bitwise is as monotonic as comparing integers. 0.15625 = = , so the exponent field is −3 + 127 = 124 = 01111100 and the mantissa field is 01 followed by zeros.
A few special encodings: an all-zero exponent means a subnormal (used for values extremely close to 0 and for ±0); an all-one exponent with an all-zero mantissa is ±∞; an all-one exponent with a non-zero mantissa is NaN — which is why 0/0 is NaN while 1/0 is Infinity, and why NaN has many bit patterns yet never equals itself.
A binary fraction can only represent sums of negative powers of two exactly: 0.5, 0.25, 0.125 and so on. in binary is the repeating fraction , so a 52-bit mantissa has to round it. The double-precision 0.1 is therefore exactly
which is slightly more than 0.1; 0.2 is also slightly more; adding the two and rounding gives 0.3000000000000000444…, while the nearest double to the literal 0.3 is 0.29999999999999998889… — two different binary numbers, so 0.1 + 0.2 === 0.3 is false. This is not a JavaScript bug; every language that uses IEEE 754 (Python, Java, C, Go) behaves the same way.
What to do depends on the situation: for money, use integer cents or a decimal library (decimal, BigDecimal, Decimal.js); for comparison, use a tolerance, Math.abs(a − b) < ε; for display, use toFixed(2) only at the very last step; for counting, use integers — double precision represents every integer up to exactly, and beyond that BigInt is the answer. The last multiple-choice question in the course asks whether the stored 0.1 is larger or smaller than the true value, and the answer is “larger” — the 55511… after the 18th digit of the exact expansion shows why.
BigInt bit operations are not covered.Math.fround, half precision and bfloat16 are not covered.0x.10000000 is −128, not −0, and −1 is all ones.>> is division by 2”: for negatives it rounds down rather than towards zero: −5 >> 1 gives −3 while Math.trunc(−5 / 2) gives −2.toFixed solves the money problem”: toFixed only rounds for display, and the error from the intermediate arithmetic has already accumulated; money should use integer cents from the start.Int32Array and |0 all run on 32-bit two's complement and do overflow; a Number above loses integer precision.& 0xFF, >>> 24, | (1 << 3), 0o644 — after lessons 11–15 you can see at a glance which bits each of these takes or sets.
The overflow in lesson 10 and the rounding in lesson 17 explain the great majority of these bugs: for the first, widen the type or use BigInt; for the second, switch to integer cents or a decimal library.
A subnet mask is an AND mask (lesson 11): 192.168.1.37 & 255.255.255.0 = 192.168.1.0. And chmod 755 / 644, plus “why will my script not run” (lesson 15).
Two's complement, overflow, the XOR swap, shift-based multiply and divide, the IEEE 754 fields and 0.1 + 0.2 are the most commonly asked basics, and the checker in each lesson is a self-test.
Most lessons allow leading zeros to be omitted (1011 and 00001011 both count); the lessons marked “8-bit two's complement” require exactly 8 bits, because the width is part of the answer.
0x needed?No to both: ff, FF and 0xFF are all accepted.
Two readings of the same bits: unsigned treats the top bit as and signed treats it as . In 8 bits 11111111 is 255 unsigned and −1 signed.
The double's mantissa and exponent are expanded into a rational number by definition and then divided out to get every decimal digit — it is not an approximation, it is the exact decimal representation of that binary number.
In the current browser's localStorage; nothing is uploaded. The “share this lesson” link carries only the lesson number, not your progress.
The whole course runs locally in the browser: base conversion, bit operations and the float field breakdown and exact expansion are all pure in-page calculations with no server request, and progress is stored in local localStorage.
chmod utility — the definitions of symbolic and octal modes: https://pubs.opengroup.org/onlinepubs/9799919799/utilities/chmod.html(访问日期:2026-09-09)Updated 2026-09-09
17 lessons: binary/octal/hex conversion, bit toggles, two's complement and overflow, AND/OR/XOR/shifts, chmod permission bits, IEEE 754 fields and why 0.1 + 0.2 is not 0.3
Goal数值面板里是二进制 1011。它等于十进制多少?
每一位的「位权」是 2 的幂:最右边是 2⁰=1,往左依次 2、4、8、16……把为 1 的位的权相加就是十进制值:1011 = 8 + 0 + 2 + 1 = 11。面板里点任何一位都能立刻看到十进制随之变化——比背口诀更快建立直觉。