Number System and Base Conversion
Bit manipulation begins before the first &, |, or ^. You need to be comfortable reading the same value in different number systems: decimal for humans, binary for bits, octal for 3-bit groups, and hexadecimal for compact 4-bit groups.
A number system is defined by its base, also called its radix. Base conversion is not magic: the value stays the same, but the groups used to write it change.
Positional Notation
In base b, each position has a place value. From right to left, the place values are 1, b, b2, b3, .... A digit tells how many of that place value are used. Digits stop at b - 1 because reaching b creates one full group, which is written as 1 in the next position and 0 in the current position.
dkdk-1...d1d0 in base b means:
d[k] * b^k + d[k-1] * b^(k-1) + ... + d[1] * b + d[0]
347 base 10 = 3 * 10^2 + 4 * 10^1 + 7 * 10^0
1011 base 2 = 1 * 2^3 + 0 * 2^2 + 1 * 2^1 + 1 * 2^0 = 11
2F base 16 = 2 * 16^1 + 15 * 16^0 = 47
Common Bases in Programming
| Base | Name | Digits | C++ literal style | Why it matters |
|---|---|---|---|---|
| 2 | Binary | 0, 1 | 0b101010 | Actual bit patterns used by bitwise operators. |
| 8 | Octal | 0..7 | 052 | Each octal digit equals exactly 3 binary bits. |
| 10 | Decimal | 0..9 | 42 | Default notation humans usually use. |
| 16 | Hexadecimal | 0..9, A..F | 0x2A | Each hex digit equals exactly 4 binary bits, so it is ideal for masks. |
Converting Decimal to Any Base
To convert decimal N to base b, repeatedly divide by b. Record each remainder. The first remainder is the rightmost digit, so read the remainders from bottom to top.
Why it works: every number can be written as N = b * quotient + remainder. The remainder is the rightmost digit because everything to its left is a multiple of b. Dividing by b removes that rightmost digit and exposes the next one.
Convert 45 decimal to binary:
45 / 2 = 22 remainder 1
22 / 2 = 11 remainder 0
11 / 2 = 5 remainder 1
5 / 2 = 2 remainder 1
2 / 2 = 1 remainder 0
1 / 2 = 0 remainder 1
Read bottom-to-top: 101101
45 = 101101 base 2
Convert 687 decimal to hexadecimal:
687 / 16 = 42 remainder 15 -> F
42 / 16 = 2 remainder 10 -> A
2 / 16 = 0 remainder 2 -> 2
Read bottom-to-top: 2AF
687 = 2AF base 16
Converting Any Base to Decimal
To convert from base b to decimal, expand every digit by its positional weight and sum the terms.
Why it works: digits in base b already mean digit * place value. Decimal conversion simply evaluates that same value using decimal arithmetic.
Convert 101101 base 2 to decimal:
1 * 2^5 + 0 * 2^4 + 1 * 2^3 + 1 * 2^2 + 0 * 2^1 + 1 * 2^0
= 32 + 0 + 8 + 4 + 0 + 1
= 45
Faster Mental Method: Left to Right
Instead of writing powers explicitly, process digits from left to right. Repeatedly multiply the current answer by the base and add the next digit.
2AF base 16:
ans = 0
ans = ans * 16 + 2 = 2
ans = ans * 16 + 10 = 42
ans = ans * 16 + 15 = 687
Why it works: adding a new digit on the right shifts the old value one position left, which means multiply by the base, then add the new digit.
Converting Negative Numbers
For ordinary bases such as binary, octal, decimal, hexadecimal, or base 7, the base itself is positive. A negative value is handled by converting the absolute value and then attaching a leading minus sign. The sign is not one of the base digits.
Simple logic: the digits describe the size; the minus sign says "take the negative of that size." So -1011012 means -(1011012).
Negative Decimal to Desired Base
To convert a negative decimal number -N to base b:
- Ignore the sign and convert
Nto basebusing repeated division. - Put
-in front of the converted digits.
Convert -45 decimal to binary:
Convert +45 first:
45 / 2 = 22 remainder 1
22 / 2 = 11 remainder 0
11 / 2 = 5 remainder 1
5 / 2 = 2 remainder 1
2 / 2 = 1 remainder 0
1 / 2 = 0 remainder 1
+45 = 101101 base 2
-45 = -101101 base 2
Negative Desired Base to Decimal
To convert a negative number written in base b back to decimal, remove the leading minus sign, convert the remaining digits normally, and then negate the decimal answer.
Convert -101101 base 2 to decimal:
Ignore the sign first:
101101 base 2 = 1 * 2^5 + 0 * 2^4 + 1 * 2^3 + 1 * 2^2 + 0 * 2 + 1
= 32 + 8 + 4 + 1
= 45
Apply the sign:
-101101 base 2 = -45 decimal
-1011012 is mathematical signed notation in a positive base, not an exotic negative-radix system and not a fixed-width two's-complement bit pattern. For example, -45 in an 8-bit signed integer is stored as 11010011, not as the characters -101101. The next section shows the conversion, and the next post goes deeper into storage details.
Signed Binary and Two's Complement
If someone says "signed binary" in programming, they usually mean a fixed-width two's-complement representation. You must know the width first, such as 8-bit, 16-bit, 32-bit, or 64-bit. The same decimal value has different signed binary strings at different widths.
Simple logic: with w bits, the machine has exactly 2w bit patterns. Read as unsigned, they go from 0 to 2w - 1. Fixed-width arithmetic behaves like a circle: after 2w - 1, the next value wraps back to 0.
For a negative value n = -x, two's complement stores the pattern that is x steps before zero on that circle. That pattern is 2w - x. Since n is -x, the same formula is written as 2w + n.
Range of a signed w-bit integer: -2w - 1 to 2w - 1 - 1
This range comes from splitting the circle of 2w patterns into two equal halves. Patterns whose leftmost bit is 0 are the lower half, so they stay non-negative: 0 to 2w - 1 - 1. Patterns whose leftmost bit is 1 are the upper half, so two's complement reads them by subtracting one full circle: 2w.
| Upper-half pattern as unsigned | Two's-complement signed value | Meaning |
|---|---|---|
2w - 1 | 2w - 1 - 2w = -2w - 1 | First negative value. |
2w - 1 | (2w - 1) - 2w = -1 | Last pattern before wrapping to zero. |
For example, with 8 bits, the lower half 0 to 127 stays positive. The upper half 128 to 255 becomes negative by subtracting 256: 128 - 256 = -128 and 255 - 256 = -1. That is why the 8-bit signed range is -128 to 127.
▶ Visual: Two's-Complement Circle
Step through an 8-bit circle to see why unsigned 128..255 becomes signed -128..-1.
Negative Decimal to Signed Binary
The most practical hand method is to write the positive magnitude in w bits, then take its two's complement. The 2w + n formula gives the same result, but the bit operation is usually easier to understand first.
To convert a negative decimal number -x to w-bit signed binary:
- Check that
-xis inside the signedw-bit range. - Convert
x, the positive magnitude, to binary using exactlywbits. - Invert every bit.
- Add
1, keeping onlywbits.
Convert -45 decimal to 8-bit signed binary:
8-bit signed range = -128 to 127, so -45 fits.
Step 1: write +45 in 8 bits
45 decimal = 00101101
Step 2: invert every bit
00101101 -> 11010010
Step 3: add 1
11010010
+ 1
---------
11010011
Therefore:
-45 as 8-bit signed binary = 11010011
Why this works: inverting the bits gives the one's complement. Adding 1 gives the two's complement, the pattern that cancels the positive magnitude under fixed-width wraparound. In 8-bit arithmetic, 00101101 is 45 and 11010011 is the pattern that makes 45 + 11010011 wrap to 0.
Important shortcut: the same conversion can be computed as 2w - x, or 2w + n when the original value is n = -x. For -45 in 8 bits: 28 + (-45) = 256 - 45 = 211, and 211 is 11010011.
This matters because a negative signed value is stored as a large unsigned pattern in the upper half of the w-bit circle. Encoding uses 2w + n; decoding that upper-half pattern reverses the idea with U - 2w.
Signed Binary to Decimal
To convert a w-bit signed binary string to decimal:
- If the leftmost bit is
0, convert it as an ordinary positive binary number. - If the leftmost bit is
1, convert it as an unsigned valueU, then computeU - 2w.
Convert 11010011 as 8-bit signed binary:
Leftmost bit is 1, so the value is negative.
Unsigned value:
11010011 base 2 = 211 decimal
Signed value:
211 - 2^8 = 211 - 256 = -45
Therefore:
11010011 as 8-bit signed binary = -45
Why subtract 2w? A leading 1 means the unsigned value is in the negative half of the circle, so subtract one full circle to get the signed value.
11010011 as an 8-bit signed number is -45, but as a 16-bit signed number written as 00000000 11010011, it is 211. A signed interpretation always needs the bit width.
Fast Conversion Between Binary, Octal, and Hex
Binary, octal, and hexadecimal are special because their bases are powers of two: 8 = 23 and 16 = 24. That means conversion can be done by grouping bits instead of doing full arithmetic.
Simple logic: one hex digit matches exactly 4 bits because 16 = 24. One octal digit matches exactly 3 bits because 8 = 23.
Binary to Hexadecimal
Group binary bits into chunks of four from right to left. Pad the leftmost group with zeros if needed. Convert each 4-bit group to one hex digit.
Convert 110101101 base 2 to hexadecimal:
Pad left: 0001 1010 1101
Groups: 0001 1010 1101
Hex: 1 A D
110101101 base 2 = 1AD base 16
Hexadecimal to Binary
Replace each hex digit by its 4-bit binary group.
Convert 0x2F to binary:
2 -> 0010
F -> 1111
0x2F = 0010 1111 base 2
Binary to Octal
Octal uses 3-bit groups because 8 = 23.
Convert 101101 base 2 to octal:
Group by 3 bits: 101 101
Octal digits: 5 5
101101 base 2 = 55 base 8
Converting From One Base to Another
The most reliable general strategy is a two-step bridge through decimal:
Simple logic: representation changes, value does not. Decimal is just a familiar checkpoint before regrouping the same value into the target base.
- Convert the source number from base
ato decimal. - Convert that decimal value to the target base
b.
Convert 735 base 8 to hexadecimal:
Step 1: octal -> decimal
735 base 8 = 7 * 8^2 + 3 * 8 + 5 = 477
Step 2: decimal -> hexadecimal
477 / 16 = 29 remainder 13 -> D
29 / 16 = 1 remainder 13 -> D
1 / 16 = 0 remainder 1 -> 1
735 base 8 = 1DD base 16
When both bases are powers of two, skip decimal and regroup through binary bits instead.
Fractional Parts
Fractional conversion has two common directions: decimal fraction to another base, and source-base fraction back to decimal.
First, understand what a decimal with a fractional part means. The same place-value idea continues after the decimal point, but now each step divides by 10 instead of multiplying by 10.
365.42
= 3 * 10^2 + 6 * 10^1 + 5 * 10^0 + 4 * 10^-1 + 2 * 10^-2
= 300 + 60 + 5 + 0.4 + 0.02
So the left side has ones, tens, hundreds, and so on. The right side has tenths, hundredths, thousandths, and so on. In base b, the same idea becomes b-1, b-2, b-3, ....
After the point, place values keep dividing by the base:
d[k]...d[1]d[0].d[-1]d[-2]...d[-m] base b means:
d[k] * b^k + ... + d[1] * b + d[0]
+ d[-1] * b^-1 + d[-2] * b^-2 + ... + d[-m] * b^-m
Decimal Fraction to Base
To convert a decimal fraction to base b, multiply the fraction by b. The integer part of the result becomes the next digit. Keep the remaining fraction and repeat.
Why it works: suppose the answer is 0.d1d2d3... in base b. Its value is d1 * b-1 + d2 * b-2 + d3 * b-3 + .... Multiplying by b gives d1 + d2 * b-1 + d3 * b-2 + ..., so d1 becomes the integer part. Remove it, repeat, and the next digit becomes visible.
Convert 0.625 decimal to binary:
0.625 * 2 = 1.25 -> digit 1, remaining 0.25
0.25 * 2 = 0.5 -> digit 0, remaining 0.5
0.5 * 2 = 1.0 -> digit 1, remaining 0
0.625 decimal = 0.101 base 2
In this example, 0.625 * 2 = 1.25 shifts the 1 / 2 place in front of the point, so the first bit is 1. The remaining 0.25 is the still-hidden part after that shift. Multiplying it by 2 shifts again; the integer part is 0, so the second bit is 0. One more shift gives integer part 1, so the third bit is 1.
Base Fraction to Decimal
To convert a fractional number from base b to decimal, expand every digit using positional weights. Digits left of the point use non-negative powers like b0, b1, b2. Digits right of the point use negative powers: b-1, b-2, b-3, and so on.
Why it works: digits after the point use the negative-power weights from the formula above. The first digit has weight b-1 = 1 / b, the second has weight b-2 = 1 / b2, and so on.
Convert 101.101 base 2 to decimal:
Integer side:
1 * 2^2 + 0 * 2^1 + 1 * 2^0 = 4 + 0 + 1 = 5
Fraction side:
1 * 2^-1 + 0 * 2^-2 + 1 * 2^-3
= 1/2 + 0/4 + 1/8
= 0.5 + 0 + 0.125
= 0.625
Final answer:
101.101 base 2 = 5.625 decimal
Faster Fraction Method: Right to Left
The fractional side has a useful mirror trick. For digits after the point, process from right to left. Repeatedly add the current digit, then divide by the base.
Convert 0.101 base 2 to decimal:
Process fractional digits from right to left: 1, 0, 1
ans = 0
ans = (ans + 1) / 2 = 0.5
ans = (ans + 0) / 2 = 0.25
ans = (ans + 1) / 2 = 0.625
0.101 base 2 = 0.625 decimal
Why it works: the rightmost fractional digit has the smallest place value. Dividing by the base moves the partial answer one place farther right. So 0.1012 becomes (1 + (0 + (1 / 2)) / 2) / 2, which equals 0.625.
Fraction Horner form: for 0.d1d2...dk in base b, scan from dk to d1 using ans = (ans + digit) / b.
When converting decimal fractions to another base, some values never terminate. For example, 0.1 repeats forever in base 2, which is why floating-point arithmetic can produce results like 0.30000000000000004.
Common Mistakes
- Reading digits as decimal:
10102is ten, but101010is one thousand ten. - Forgetting to reverse remainders: repeated division produces digits from least significant to most significant.
- Treating the minus sign as a digit: for normal positive bases, convert the absolute value first and keep the sign separately.
- Interpreting signed binary without width:
11010011needs a width before it can be read as a signed two's-complement value. - Using positive powers after the point: fractional digits use
b-1, b-2, ..., notb1, b2, .... - Using invalid digits:
8is invalid in octal, andGis invalid in hexadecimal. - Dropping leading zeros too early: leading zeros do not change the value, but they matter when showing fixed-width bit patterns such as
00001010. - Confusing value with representation:
42,0b101010,052, and0x2Aare different representations of the same value.
Summary
- A base is a grouping rule. Moving left multiplies the place value by the base.
- Decimal to base uses remainders because
N mod bis the rightmost digit. - Base to decimal adds each digit times its place value.
- For ordinary positive bases, the minus sign stays outside the digits.
- Signed binary uses fixed-width two's complement, so width always matters.
- Binary, octal, and hex are easy to regroup because
8 = 23and16 = 24. - Fractional digits use place values smaller than one:
1 / b,1 / b2, and so on.
With number systems in place, the next post explains how integers are actually stored in binary, including unsigned ranges, signed numbers, two's complement, overflow, and sign extension.
Practice Problems
These problems reinforce base conversion, binary strings, and hexadecimal representation.
- LeetCode 67 - Add Binary binary strings add two base-2 numbers digit by digit.
- LeetCode 504 - Base 7 decimal to base repeated division with sign handling.
- LeetCode 168 - Excel Sheet Column Title base 26 conversion with 1-indexed digits.
- LeetCode 171 - Excel Sheet Column Number base to decimal Horner's method on alphabet digits.
- LeetCode 405 - Convert a Number to Hexadecimal hex base-16 conversion and two's-complement edge cases.
- LeetCode 483 - Smallest Good Base advanced positional notation plus geometric sums.