What is `10`

? If this is your first time learning about the binary number system, then this question may seem odd. Of course itâ€™s ten, right?

Letâ€™s try something different. Have you ever heard this joke?

There are

`10`

types of people in the world: those who understand binary and those who donâ€™t.

Unless youâ€™re familiar with binary numbers, this probably doesnâ€™t make much sense. But by the end of this post, youâ€™ll come to appreciate this and many other awful developer jokes!

In this beginnerâ€™s tutorial, weâ€™ll look at everything you need to know about the binary number system, but weâ€™ll also take a quick look at decimal and hexadecimal, as theyâ€™re closely related. Iâ€™ll include relevant bits of code and real-life examples to help you appreciate the beauty of binary.

## Table of Contents

- What Is a Number System?
- The Binary Number System (Base 2)
- The Hexademical Number System (Base 16)
- Signed Binary Number System: Twoâ€™s Complement
- Basic Arithmetic in the Binary Number System
- The Binary Number System: Additional Topics for Exploration

## What Is a Number System?

Before we look at binary, letâ€™s take a step back and discuss number systems *in general*.

Now, it may be strange to think of number â€śsystemsâ€ť in the plural if this is your first time learning about them. Thatâ€™s because the majority of the world is familiar with just one: the **decimal number system** (aka â€śbase tenâ€ť), also known as the **Arabic number system**. This system has digits ranging from `0`

to `9`

, which we use to form numbers in our daily lives.

For example, in the decimal number system, `579`

expands to this:

`579 = 5(10`

^{2}) + 7(10^{1}) + 9(10^{0}) = 500 + 70 + 9

As a kid, you were taught that the `5`

in `579`

is in the â€śhundreds place,â€ť the `7`

is in the â€śtens place,â€ť and the `9`

is in the ones place. Notice that the `5`

is multiplied by one hundred (`10`

), the ^{2}`7`

by ten (`10`

), and the ^{1}`9`

by one (`10`

) to form the decimal number ^{0}`579`

. Makes sense, right?

Here, the number `10`

is what we call the **base** (aka **radix**) of our number system. Notice the powers of `10`

in the expanded expression above: `10`

, ^{2}`10`

, and ^{1}`10`

. For this reason, the terms ^{0}*decimal* and *base 10* are interchangeable.

In the decimal number system, a number is represented by placing digits into â€śbucketsâ€ť that represent **increasing powers of ten**, starting with `10`

in the rightmost â€śbucket,â€ť followed by ^{0}`10`

to its immediate left, and so on infinitely:^{1}

Any unused buckets to the far left have an implicit value of `0`

in them. We usually trim leading zeros because there is no use in saying `00579`

when thatâ€™s mathematically identical to `579`

.

Why did humans pick `10`

to be the base of their preferred number system? Most likely because weâ€™re born with ten fingers and ten toes, and weâ€™re used to counting with our fingers when weâ€™re young. So itâ€™s simply natural for us to use this number system!

### Bases, Exponents, and Digits

As Iâ€™ve already hinted, the decimal number system (base `10`

) isnâ€™t the only one in existence. Letâ€™s use a more general mathematical notation to represent number systems beyond just our familiar one.

In a number system with a fixed base of `b`

, the available digits range from `0`

to `b - 1`

. For example, in the decimal number system (`b = 10`

), we can only use the digits `0, 1, 2, ..., 9`

. When you â€śrun outâ€ť of digits in a single bucket, you carry over a one to the next power of the base. For example, to get to the number after `99`

, you carry a one to the next power of ten: `100`

.

Now, suppose that we have a string of digits `d`

(where _{1} d_{2} ... d_{n}`n`

is just the number of digits). Maybe thatâ€™s `d`

from our earlier example. That string expands like this:_{1} d_{2} ... d_{n} = 579

`d`

_{1}b^{n-1} + d_{2}b^{n-2} + ... + d_{n}b^{0}

And you can visualize that like this:

Using our same example, `d`

_{1}b^{n-1} + d_{2}b^{n-2} + ... + d_{n}b^{0} = 5(10^{2}) + 7(10^{1}) + 9(10^{0})

Again, we have buckets from right to left in increasing powers of our base (`10`

).

Note: The rightmost bucket will always represent`d`

in any number system. Why? Because any base raised to the power of_{n}`0`

is just`1`

.

Now, in reality, you can have a number system that uses a base of `2`

, `3`

, `4`

, `120`

, and so on. Some of these have special names because theyâ€™re used more often than others:

Base | Name | Description |
---|---|---|

1 | Unary | Also known as tallying. A number `n` is represented by picking an arbitrary character and repeating it `n` times (e.g., `xxxx` would be `4` ). |

2 | Binary | Only two digits: zero and one. Most commonly used in computing. Everything on a computer is, at the lowest possible level, stored using the binary number system. |

8 | Octal | Only eight digits are available: `0â€“7` . |

16 | Hexadecimal | Fifteen digits: `0â€“9` and `aâ€“f` . Often used to express binary strings more compactly. |

60 | Sexagesimal | How many seconds are in a minute? How many minutes in an hour? This is the basis of the modern circular coordinate system (degrees, minutes, and seconds). |

For this reason, when discussing number systems, we usually subscript a number with its base to clarify its value. Alternatively, you can prepend a number with a certain string (usually `0b`

for binary or `0x`

/`#`

for hexadecimal). So weâ€™d write `579`

as `579`

, or the binary number _{10}`1001`

as `1001`

(or _{2}`0b1001`

). Otherwise, if we were to merely write the number `1001`

without providing any context, nobody would know whether thatâ€™s in binary, octal, decimal, hexadecimal, and so on because the digits `0`

and `1`

are valid in all of those number systems, too!

Note: When not comparing number systems, we usually assume that a given number is in decimal unless otherwise noted, and thus the subscript is omitted.

## The Binary Number System (Base 2)

So far so goodâ€”weâ€™re all familiar with decimal numbers because we use them everyday. But whatâ€™s the deal with the binary number system?

By definition, the **binary number system** has a base of `2`

, and thus we can only work with two digits to compose numbers: `0`

and `1`

. Technically speaking, we donâ€™t call these digitsâ€”theyâ€™re called **bits** in binary lingo.

Each â€śbucketâ€ť in a binary string represents an increasing power of two: `2`

, ^{0}`2`

, ^{1}`2`

, and so on.^{2}

The leftmost bit is called the **most significant bit (MSB)**, while the rightmost bit is called the **least significant bit (LSB)**.

Here are some examples of representing decimal numbers in the binary number system:

- Zero:
`0`

. Expansion:_{10}= 0_{2}`0 (2`

^{0}) - One:
`1`

. Expansion:_{10}= 1_{2}`1(2`

^{0}) - Two:
`2`

. Expansion:_{10}= 10_{2}`1(2`

^{1}) + 0(2^{0}) - Three:
`3`

. Expansion:_{10}= 11_{2}`1(2`

^{1}) + 1(2^{0}) - Four:
`4`

. Expansion:_{10}= 100_{2}`1(2`

^{2}) + 0(2^{1}) + 0(2^{0}) - Five:
`5`

. Expansion:_{10}= 101_{2}`1(2`

^{2}) + 0(2^{1}) + 1(2^{0})

Note: Like in the decimal number system, leading zeros are usually stripped from binary strings. The only exception is if youâ€™re working with a signed binary number system, where a leading zero indicates that a number is positive and a leading one indicates that itâ€™s negative.

Having learned the binary number system, you should now understand the joke from earlier:

There are

`10`

types of people in the world: those who understand binary and those who donâ€™t.

Here, we really mean the binary equivalent of two, which *looks* like ten to our eyes when itâ€™s not properly subscripted: `10`

._{2} = 1 Ă— 2^{1} = 2_{10}

### Binary Is Close to the Hardware of a Computer

Why do we bother with using the binary number system in the first place? Doesnâ€™t it seem like a whole lot of extra work to represent numbers in this manner when we could instead use the decimal number system? Well, yesâ€”if youâ€™re writing these out by hand, itâ€™s certainly more work to represent (and manipulate) binary numbers.

You may not see any point in using binary if you havenâ€™t learned about computer architecture at a low level. Internally, computers are nothing more than electrical circuits tied to hardware. Current either flows through a wire or doesnâ€™tâ€”a **binary state**. Likewise, computers use **logic gates** (AND/OR/NOR/XOR) to control the flow of a programâ€™s execution, and these take binary inputs (`true`

/`false`

). The best way to represent these low-level interactions is to use the binary number system: `0`

means OFF (or `false`

in its logical form) and `1`

means ON (or `true`

).

Note: If the whole world were to agree to it, we could just as well instead treat`0`

as ON and`1`

as OFF. However, it just makes more sense to treat`0`

as OFF/falseâ€”after all, zero denotes the absence of a value. Hence, itâ€™s a natural candidate for representing things like falsehood or the lack of a current flowing through a wire.

Everything on your computerâ€”the files you save and the software you installâ€”is represented as nothing more than zeros and ones. But how is this possible?

### The ASCII Standard

Suppose you create a file on your computer and store some basic text in it:

```
echo Hello, Binary > file
```

At the end of the day, your computer canâ€™t store a character like `H`

, `e`

, `l`

, or `o`

(or even the space between two words) *literally*. Computers only know how to work with *binary*. Thus, we need some way to convert these characters to numbers. And thatâ€™s why the ASCII standard was introduced.

Formally, ASCII is referred to as a **character encoding standard**. Put more simply, itâ€™s a method of representing human-readable characters like `H`

, `e`

, `,`

, `?`

, and `9`

numerically so that computers can understand and use them like we do.

Here is a typical ASCII chart that you may have seen before:

In the ASCII standard, there are a total of 128 characters, each mapped to a unique number in binary (with an equivalent representation in decimal that we humans understand more naturally):

- Arabic digits:
`0-9`

(10) - Capital letters of the English alphabet:
`A-Z`

(26) - Lowercase letters of the English alphabet:
`a-z`

(26) - Punctuation and special characters (66)

### 1 Character = 1 Byte

In the decimal number system, weâ€™re used to working with digits. In binary, as we already saw, weâ€™re used to working with **bits**. Thereâ€™s another special group of digits in binary thatâ€™s worth mentioning: A sequence of eight bits is called a **byte**.

Here are some examples of valid bytes:

```
00000000
10000000
11101011
11111111
```

â€¦ and any other valid permutation of eight `0`

s and `1`

s that you can think of.

Why is this relevant? Because on modern computers, **characters are represented using bytes**.

Recall that the ASCII standard needs to support a total of **128 characters**. So how many unique number can we represent with `8`

bits (a byte)?

Well, using the product rule from combinatorics, we have eight â€śbuckets,â€ť each with two possible values: either a `0`

or a `1`

. Thus, we have `2 Ă— 2 Ă— ... Ă— 2 = 2`

possible values.^{8}

In decimal, this is `2`

possible values. By comparison, ^{8} = 256`2`

. And ^{7} = 128`128`

happens to be the number of characters that we want to represent.

Soâ€¦ Thatâ€™s weird, and seemingly wasteful, right? Why do we use `8`

bits (one byte) to represent a character when we could use `7`

bits instead and meet the precise character count that we need?

Good question! We use bytes because **itâ€™s not possible to evenly divide a group of 7 bits**, making certain low-level computations difficult if we decide to use

`7`

bits to represent a character. In contrast, a byte can be evenly split into powers of two:```
11101011
[1110][1011]
[11][10][10][11]
```

The key takeaway here is that we only need one byte to store one character on a computer. This means that a string of five charactersâ€”like `Hello`

â€”occupies five bytes of space, with each byte being the numerical representation of the corresponding character per the ASCII standard.

Remember the file we created earlier? Letâ€™s view its binary representation using the `xxd`

Unix tool:

```
xxd -b file
```

The `-b`

flag stands for binary. Hereâ€™s the output that youâ€™ll get:

```
00000000: 01001000 01100101 01101100 01101100 01101111 00101100 Hello,
00000006: 00100000 01000010 01101001 01101110 01100001 01110010 Binar
0000000c: 01111001 00001010 y.
```

The first line shows a sequence of six bytes, each corresponding to one character in `Hello,`

.

Letâ€™s decode the first two bytes using our knowledge of the binary number system and ASCII:

`01001000 = 1(2`

. Per our ASCII table, this corresponds to^{6}) + 1(2^{3}) = 72_{10}`H`

.`01100101 = 1(2`

, which is^{6}) + 1(2^{5}) + 1(2^{2}) + 1(2^{0}) = 101_{10}`e`

in ASCII.

Cool! Looks like the logic pans out. You can repeat this for all of the other bytes as well. Notice that on the second line, we have a leading space (from `Hello, Binary`

), represented as `2`

in ASCII (which is indeed ^{5} = 32_{10}`Space`

per the lookup table!).

By the way, whatâ€™s up with the numbers along the left-hand side of the output? What does `0000000c`

even mean? Time to explore another important number system!

## The Hexademical Number System (Base 16)

As I mentioned in the table from earlier, the hexadecimal number system is closely related to binary because itâ€™s often used to express binary numbers more compactly, instead of writing out a whole bunch of zeros and ones.

The **hexadecimal number system** has a base of `16`

, meaning its digits range from `0â€“15`

.

Note: In technical terms, a hexadecimal digit is called anibble, but youâ€™ll commonly hear people just call them â€śhex digits.â€ť

This is our first time encountering a number system whose digits are made up of more than two characters. How do we squeeze `10`

, `11`

, or `15`

into a single â€śbucketâ€ť or â€śslotâ€ť for a digit? To be clear, **this is perfectly doable** if you have clear delimiters between digits. But in reality, thatâ€™s not practical.

Letâ€™s take a step back and consider a simple hexadecimal number:

`0x42`

What does this mean to us humans in our decimal number system? Well, all we have to do is multiply each digit by its corresponding power of `16`

:

`0x42 = 4(16`

^{1}) + 2(16^{0}) = 64_{10} + 2_{10} = 66_{10}

Okay, so thatâ€™s a simple hex number. Back to the problem at hand: How do we represent the hex digits `10`

, `11`

, and so on? Hereâ€™s an example thatâ€™s pretty confusing unless we introduce some alternative notation:

`0x15`

Is this a `15`

in a single slot or a `1`

and a `5`

in two separate slots? One way to make this less ambiguous is to use some kind of delimiter between slots, but again, thatâ€™s not very practical:

`0x8[15]29`

The better solution that people came up with is to map `10â€“15`

to the the English letters `aâ€“f`

.

Note: Capitalization doesnâ€™t matter, so you can use`a-f`

or`A-F`

. Just be consistent.

Hereâ€™s an example of a hexadecimal number that uses one of these digits:

`0xf4`

And hereâ€™s its expansion:

`0xf4 = 15(16`

^{1}) + 4(16^{0}) = 240_{10} + 4_{10} = 244_{10}

Thereâ€™s nothing magical about the hexadecimal number systemâ€”it works just like unary, binary, decimal, and others. All thatâ€™s different is the base!

Before we move on, letâ€™s revisit the output from earlier when we used `xxd`

on our sample file:

```
00000000: 01001000 01100101 01101100 01101100 01101111 00101100 Hello,
00000006: 00100000 01000010 01101001 01101110 01100001 01110010 Binar
0000000c: 01111001 00001010 y.
```

The numbers along the left-hand side mark the starting byte for each line of text on the far right. For example, the first line of text (`Hello,`

) ranges from byte #0 (`H`

) to byte #5 (`,`

). The next line is marked as `00000006`

, meaning weâ€™re now looking at bytes #6 through 11 (`B`

to `r`

). Finally, the last label should make sense now that you know the hexadecimal number system: `c`

maps to `12`

, meaning the byte that follows corresponds to the twelfth character in our file.

### How to Convert Between Binary and Hexadecimal

Now that we know a bit about binary and hexadecimal, letâ€™s look at how we can convert between the two systems.

#### Binary to Hexadecimal

Say youâ€™re given this binary string and youâ€™d like to represent it in hexadecimal:

`011011100101`

While at first this may seem like a pretty difficult task, itâ€™s actually **very easy**.

Letâ€™s do a bit of a thought exercise:

In the hexadecimal number system, we have

`16`

digits from`0`

to`15`

. Over in binary land, how many bits do we need to represent these`16`

values?

The answer is four because `2`

. With four â€śbuckets,â€ť we can create the numbers zero (^{4} = 16`0000`

), one (`0001`

), ten (`1010`

), all the way up to fifteeen (`1111`

).

This means that when youâ€™re given a binary string, all you have to do is **split it into groups of four bits** and evaluate them to convert binary to hexadecimal!

```
011011100101
[0110][1110][0101]
6 14 5
```

Now we just replace `10â€“15`

with `a-f`

and weâ€™re done: `0x6e5`

.

#### Hexadecimal to Binary

What about the reverse process? How do you convert a hexadecimal number to binary?

Say youâ€™re given the hexadecimal number `0xad`

. What do we know about each hexadecimal digit? Well, from our earlier thought exercise, we know that four bits = one hex digit. So now we just have to convert each indiviual digit to its `4`

-bit binary representation and then stick each group together!

`0xad = 0b10101101`

Super easy, just like I promised.

### Real-World Application: Representing Colors with RGB/Hex

While weâ€™re on the topic of binary and hexadecimal, itâ€™s worth taking a look at one real-world use case for the things weâ€™ve learned so far: **RGB and hex colors**.

Colors have three components: red, green, and blue (RGB). With LED (light-emitting diode) displays, each pixel is really split into these three components using a color diode. If a color component is set to `0`

, then itâ€™s effectively turned off. Otherwise, its intensity is modulated between `0`

and `255`

, giving us a color format like `rgb(0-255, 0-255, 0-255)`

.

Letâ€™s consider this hex color: `#4287f5`

. What is it in the RGB format?

Well, we need to split this hex string evenly between red, green, and blue. Thatâ€™s two digits per color:

`[42][87][f5]`

Now, we simply interpret the decimal equivalent for each part:

**Red**:`42`

_{16}= 4(16^{1}) + 2(16^{0}) = 66**Green**:`87`

_{16}= 8(16^{1}) + 7(16^{0}) = 135**Blue**:`f5`

_{16}= 15(16^{1}) + 5(16^{0}) = 245

That means `#4287f5`

is really `rgb(66, 135, 245)`

! You can verify this using a Color Converter:

For practice, letâ€™s convert this to binary as well. Iâ€™ll mark the groups of four bits to make it easier to see how I did this (note: you can also convert from the decimal RGB representation if you want to):

`0x4287f5 = 0b[0100][0010][1000][0111][1111][0101]`

Now, two groups of four bits will represent one component of the color (red/green/blue):

`0b[01000010][10000111][11110101]`

Notice that each color *component* takes up a byte (`8`

bits) of space.

#### How Many Colors Are There?

As an additional exercise, how many unique colors can you possibly have in the modern RGB format?

We know that each component (red/green/blue) is represented using one byte (`8`

bits). So the colors weâ€™re used to are really `24`

-bit colors.

That means there are a whopping `2`

possible unique colors that you can generate using hex/rgb! The ^{24} = 16,777,216`24`

-bit color system is known simply as **truecolor**. And as you can see, itâ€™s capable of representing millions of colors.

Note that you could just as well have performed this calculation using hex: `#4287f5`

. There are six slots, each capable of taking on a value from `0`

to `f`

. That gives us a total of `16 Ă— 16 Ă— ... Ă— 16 = 16`

valuesâ€”the same result as before.^{6} = 16,777,216

Or, if youâ€™re using the decimal RGB format, the math still pans out: `256 Ă— 256 Ă— 256 = 16,777,216`

.

#### What Are 8-Bit Colors?

On older systems with limited memory, colors were represented using just eight bits (one byte). These **8-bit colors** had a very limited palette, which meant that most computer graphics didnâ€™t have gradual color transitions (so images looked very pixelated/grainy). With only `8`

bits to work with, you are limited to just `2`

colors!^{8} = 256

Naturally, you may be wondering: How did they split `8`

bits evenly among red, green, and blue? After all, `8`

isnâ€™t divisible by three!

Well, the answer is that *they didnâ€™t*. The process of splitting these bits among the color components is called color quantization, and the most common method (known as **8-bit truecolor**) split the bits as 3-3-2 red-green-blue. Apparently, this is because the human eye is less sensitive to blue light than the other two, and thus it simply made sense to distribute the bits heavily in favor of red and green and leave blue with one less bit to work with.

## Signed Binary Number System: Twoâ€™s Complement

Now that weâ€™ve covered decimal, binary, and hexadecimal, Iâ€™d like us to revisit the binary number system and learn how to represent negative numbers. Because so far, weâ€™ve only looked at positive numbers. How do we store the negative sign?

To give us some context, Iâ€™ll assume that weâ€™re working with standard `32`

-bit integers that most (all?) modern computers support. We could just as well look at `64`

-bit or `N`

-bit integers, but itâ€™s good to have a concrete basis for a discussion.

If we have `32`

bits to fiddle with, that means we can represent a total of `2`

(4 billion) numbers. More generally, if you have ^{32} = 4,294,967,296`N`

bits to work with, you can represent `2`

values. But weâ€™d like to split this number range evenly between negatives and positives.^{N}

Positive or negativeâ€¦ positive or negative. One thing or another thingâ€”ring a bell? That sounds like itâ€™s binary in nature. And heyâ€”weâ€™re already using binary to *store* our numbers! Why not reserve just a single bit to represent *the sign*? We can have the most significant (leading) bit be a `0`

when our number is positive and a `1`

when itâ€™s negative!

Note: This is once again one of those situations where you could just as well do the opposite, except youâ€™d have to convince the whole world to follow your chosen convention.

Earlier, when we were first looking at the binary number systems, I mentioned that you can strip leading zeros because they are meaningless. This is true except when you actually care about distinguishing between positive and negative numbers in binary. Now, we need to be carefulâ€”if you strip all leading zeros, you my be left with a leading `1`

, and that would imply that your number is negative (in a signed number system).

You can think of twoâ€™s complement as a new *perspective* or lens through which we look at binary numbers. The number `100`

ordinarily means _{2}`4`

if we donâ€™t care about its sign (i.e., we assume itâ€™s _{10}**unsigned**). But if we do care, then we have to ask ourselves (or whoever provided us this number) whether itâ€™s a signed number.

### How Does Twoâ€™s Complement Work?

What does a leading `1`

actually represent when you expand a signed binary number, and how do we convert a positive number to a negative one, and vice versa?

For example, suppose weâ€™re looking at the number `22`

, which is represented like this in unsigned binary:_{10}

`10110`

_{2}

Since weâ€™re looking at signed binary, we need to pad this number with an extra `0`

out in front (or else a leading `1`

would imply that itâ€™s negative):

`010110`

_{2}

Okay, so this is positive `22`

. How do we represent _{10}`-22`

in binary?_{10}

There are two ways we can do this: the intuitive (longer) approach and the â€śshortcutâ€ť approach. Iâ€™ll show you both, but Iâ€™ll start with the more intuitive one.

#### The Intuitive Approach: What Does a Leading 1 Denote?

Given an `N`

-bit binary string, a leading `1`

in twoâ€™s complement represents `-1`

multiplied by its corresponding power of two (`2`

). A digit of ^{N-1}`1`

in any other slot represents `+1`

times its corresponding power of two.

For example, the signed number `11010`

has this expansion:_{2}

`11010`

_{2} = -1(2^{4}) + 1(2^{3}) + 1(2^{1}) = -16_{10} + 8_{10} + 2_{10} = -6_{10}

We simply treat the leading `1`

as a negative, and that changes the resulting sum in our expansion.

#### Twoâ€™s Complement Shortcut: Flip the Bits and Add a 1

To convert a number represented in twoâ€™s complement binary to its opposite sign, follow these two simple steps:

- Flip all of the bits (
`0`

becomes`1`

and vice versa). - Add
`1`

to the result.

For example, letâ€™s convert `43`

to _{10}`-43`

in binary:_{10}

```
+43 in binary: 0101011
Flipped: 1010100
Add one: 1010101
```

What is this number? It should be `-43`

, so letâ€™s expand it by hand to verify:_{10}

`-1(2`

^{6}) + 1(2^{4}) + 1(2^{2}) + 1(2^{0}) = -64_{10} + 16_{10} + 4_{10} + 1_{10} = -43

Sure enough, the process works!

#### How Many Signed Binary Numbers Are There?

Weâ€™ve seen that in a signed binary system, the most significant bit is reserved for the sign. What does this do to our number range? Effectively, it halves it!

Letâ€™s consider `32`

-bit integers to give us a concrete basis for discussion. Whereas before we had `32`

bits to work with for the magnitude of an unsigned number, we now have only `31`

for the magnitude of a signed number:

```
Unsigned magnitude bits: [31 30 29 ... 0]
Signed magnitude bits: 31 [30 29 ... 0]
```

We went from having `2`

numbers to ^{32}`2`

positive and negative numbers, which is precisely half of what we started with!^{31}

More generally, if you have an `N`

-bit signed binary string, there are going to be `2`

values, split evenly between ^{N}`2`

positives and ^{N-1}`2`

negatives.^{N-1}

Notice that the number zero gets bunched in with the positives and not the negatives:

```
Signed zero: 0 0 0 0 ... 0 0 0 0
Bits: 31 30 29 28 ... 3 2 1 0
```

As weâ€™re about to see, this has an interesting consequence.

#### What Is the Largest Signed 32-bit Integer?

The largest signed 32-bit integer is positive, meaning its leading bit is a zero. So we just need to maximize the remaining bits to get the largest possible value:

```
Num: 0 1 1 1 ... 1
Bits: 31 30 29 28 ... 0
```

This is `2`

, which is ^{31} - 1`2,147,483,647`

. In Java, this number is stored in `Integer.MAX_VALUE`

, and in C++, itâ€™s `std::numeric_limits`

More generally, for an `N`

-bit system, the largest signed integer is `2`

.^{N-1}-1

Why did we subtract a one at the end? Because as I mentioned in the previous section, the number zero gets grouped along with the positives when we split our number range:

```
Signed zero: 0 0 0 0 ... 0 0 0 0
Bits: 31 30 29 28 ... 3 2 1 0
```

So to get our largest signed integer, we need to subtract oneâ€”weâ€™ve effectively â€ślostâ€ť a magnitude of one.

##### Real-World Application: Video Game Currency

In video games like RuneScape that use `32`

-bit signed integers to represent in-game currency, the max â€ścash stackâ€ť that you can have caps out at exactly `2`

, which is roughly 2.1 billion.^{31} - 1

Now you know why! If youâ€™re wondering why they donâ€™t just use unsigned ints, itâ€™s because RuneScape runs on Java, and Java doesnâ€™t support unsigned ints (except in SE 8+).

#### What Is the Smallest Signed 32-bit Integer?

This occurs when we set the leading bit to be a `1`

and set all remaining bits to be a `0`

:

```
Num: 1 0 0 0 ... 0
Bits: 31 30 29 28 ... 0
```

Why? Because recall that in the expansion of negative numbers in twoâ€™s complement binary, the leading `1`

is a `-1`

times `2`

, and a ^{N-1}`1`

in any other position will be treated as `+1`

times its corresponding power of two. Since we want the smallest negative number, we donâ€™t want any positive terms, as those take away from our magnitude. So we set all remaining bits to be `0`

.

**Answer**: `-2`

^{31}

In Java, this value is stored in `Integer.MIN_VALUE`

.

In C++, itâ€™s in `std::numeric_limits`

Generalizing things once again, if we have an `N`

-bit system, the smallest representable signed int is `-2`

.^{N-1}

## Basic Arithmetic in the Binary Number System

Spoiler: Adding, subtracting, multiplying, and dividing numbers in the binary number system is **exactly the same** as it is in decimal!

### Adding Binary Numbers

Weâ€™ll first revisit what we learned in elementary school for decimal numbers and then look at how to add two binary numbers.

To add two numbers in the decimal number system, you stack them on top of one another visually and work your way from right to left, adding two digits and â€ścarrying the oneâ€ť as needed.

Now you should know what carrying the one really means: When you run out of digits to represent something in your fixed-base number system (e.g., `13`

isnâ€™t a digit in base `10`

), you represent the part that you can in the current digits place and move over to the next power of your base (the â€ścolumnâ€ť to the left of your current one).

For example, letâ€™s add `24`

and `18`

in decimal:

```
24
+ 18
â€”â€”â€”â€”
42
```

We first add the `4`

and `8`

to get `12`

, which is not a digit we support in the decimal number system. So we represent the part that we can (`2`

) and carry the remaining value (ten) over to the next column as a `1`

(`1 Ă— 10`

). There, we have ^{1} = 10_{10}`1 + 2 + 1 = 4`

:

```
1 <-- carried
24
+ 18
â€”â€”â€”â€”â€”â€”â€”â€”
42
```

Now, letâ€™s add these same two numbers (`24`

and _{10}`18`

) using the binary number system:_{10}

```
11000
+ 10010
â€”â€”â€”â€”â€”â€”â€”
101010
```

We work from right to left:

- Ones place:
`0 + 0 = 0`

- Twos place:
`0 + 1 = 1`

- Fours place:
`0 + 0 = 0`

- Eights place:
`1 + 0 = 1`

- Sixteens place:
`1 + 1 = 10`

(two)_{2}

That last step deserves some clarification: When we try to add the two ones, we get `1`

(two), so we put a _{2} + 1_{2} = 10_{2}`0`

in the current column and carry over the `1`

to the next power of two, where we have a bunch of implicit leading zeros:

```
1 <-- carry bits
0000 ... 00011000
0000 ... + 00010010
â€”â€”â€”â€”â€”â€”â€”â€”â€”â€”â€”â€”â€”â€”â€”â€”â€”â€”â€”â€”â€”
0000 ... 00101010
```

In that column, `1 (carried) + 0(implicit) = 1`

.

If we expand the result, weâ€™ll find that itâ€™s the same answer we got over in decimal:

`1(2`

^{5}) + 1(2^{3}) + 1(2^{1}) = 32 + 8 + 2 = 42_{10}

Letâ€™s look at one more example to get comfortable with carrying bits in binary addition: `22`

, which we know to be _{10} + 14_{10}`36`

:_{10}

```
10110
+ 01110
â€”â€”â€”â€”â€”â€”â€”
100100
```

Something interesting happens when we look at the twos place (the `2`

column): We add ^{1}`1`

to _{2}`1`

, giving us two (_{2}`10`

), so we put a zero in the _{2}`2`

column and carry the remaining one.^{1}

Now we have three ones in the `2`

column: ^{2}`1`

(three). So we put a one in the _{2}(carried) + 1_{2}(operand1) + 1_{2}(operand2) = 11_{2}`2`

column and carry a one yet again. Rinse and repeat!^{2}

```
1111 <-- carry bits
0000 ... 00010110
0000 ... + 00001110
â€”â€”â€”â€”â€”â€”â€”â€”â€”â€”â€”â€”â€”â€”â€”â€”â€”â€”â€”â€”â€”
0000 ... 00100100
```

Once again, itâ€™s a good idea to expand the result so you can verify your work:

`1(2`

^{5}) + 1(2^{2}) = 32_{10} + 4_{10} = 36_{10}

Note: Weâ€™ve only looked at examples of adding two binary numbers, but you could just as well stack`x`

numbers on top of one another and add them in binary, just like you would in decimal. How far ahead you need to carry your ones depends on the result that you get in a particular column, represented as a binary string.

### Subtracting Binary Numbers

Subtraction is addition with a negative operand: `a - b = a + (-b)`

. Now that we know how to represent negative numbers in the binary system thanks to twoâ€™s complement, this should be a piece of cake: **negate the second operand and perform addition**.

For example, whatâ€™s `12`

? In decimal, we know this to be _{10} - 26_{10}`-14`

. Over in binary, we know that _{10}`12`

is _{10}`01100`

. What about `-26`

? Weâ€™ll represent that using twoâ€™s complement._{10}

We start by first representing `26`

in binary:_{10}

`+26`

_{10} = 011010_{2}

Now we negate it by flipping the bits and adding one:

```
26 in binary: 011010
Flipped: 100101
Add one: 100110 = -26
```

Stack up your operands and add them like we did before:

```
11 <-- carry bits
001100
+ 100110
â€”â€”â€”â€”â€”â€”â€”â€”â€”â€”
110010
```

Notice that the result has a leading one, which we know denotes a negative number in signed binary. So we at least got the sign part right! Letâ€™s check the magnitude:

`-1(2`

^{5}) + 1(2^{4}) + 1(2^{1}) = -32_{10} + 16_{10} + 2_{10} = -14_{10}

See what I mean? Adding and subtracting numbers in the binary number system is just as easy as it is over in decimal.

### Multiplying Binary Numbers

Letâ€™s remind ourselves how we multiply numbers in decimal:

```
21
x 12
â€”â€”â€”â€”
```

Remember the process? We multiply the `2`

by each digit in the first multiplicand and write out the result under the bar:

```
21
x 12
â€”â€”â€”â€”
42
```

Then we move on to the `1`

in `12`

and repeat the process, but adding a `0`

in the right column of the result. Add the two intermediate products to get the answer:

```
21
x 12
â€”â€”â€”â€”â€”
42
+ 210
â€”â€”â€”â€”â€”
252
```

Guess what? The process is exactly the same in the binary number system!

Letâ€™s multiply these same two numbers in binary. They are `21`

and _{10} = 010101`12`

:_{10} = 01100

```
010101
x 01100
â€”â€”â€”â€”â€”â€”â€”â€”â€”
```

Obviously, this is going to be more involved in binary since weâ€™re working with bits (and thus longer strings), but the logic is still the same. In fact, beyond having to write out so many intermediate results, we actually have it much easier over in binary. Whenever a digit is `1`

, you simply copy down the first multiplicand, padded with zeros. Whenever itâ€™s a zero times the first multiplicand, the result is zero!

```
010101
x 01100
â€”â€”â€”â€”â€”â€”â€”â€”â€”â€”â€”â€”
000000
0000000
01010100
010101000
+ 0000000000
â€”â€”â€”â€”â€”â€”â€”â€”â€”â€”â€”â€”
0011111100
```

Expanding this in binary, we get:

`0011111100`

_{2} = 1(2^{7}) + 1(2^{6}) + 1(2^{5}) + 1(2^{4}) + 1(2^{3}) + 1(2^{2}) = 252_{10}

Easy peasy. The same process applies regardless of whether your multiplicands are signed or unsigned.

### Dividing Binary Numbers

Letâ€™s divide `126`

by _{10}`12`

using long division:_{10}

```
0 1 0 . 5
_______
12 |1 2 6
- 1 2
â€”â€”â€”â€”
0 6
- 0
â€”â€”â€”â€”â€”â€”
6 0
- 6 0
â€”â€”â€”â€”â€”
0
```

Answer: `10.5`

.

Now letâ€™s repeat the process over in the binary number system. Note that Iâ€™m going to strip leading zeros to make my life easier since weâ€™re working with two unsigned numbers:

```
_______
1100 |1111110
```

Take things one digit at a time, and reference this useful YouTube video if you get stuck:

```
0 0 0 1 0 1 0 . 1
______________
1 1 0 0 |1 1 1 1 1 1 0 . 0
-0
â€”â€”
1 1
- 0
â€”â€”â€”â€”
1 1 1
- 0
â€”â€”â€”â€”â€”â€”
1 1 1 1
- 1 1 0 0
â€”â€”â€”â€”â€”â€”â€”â€”
1 1 1
- 0
â€”â€”â€”â€”â€”â€”â€”â€”â€”â€”
1 1 1 1
- 1 1 0 0
â€”â€”â€”â€”â€”â€”â€”â€”â€”
0 0 1 1 0
- 0
â€”â€”â€”â€”â€”â€”â€”â€”â€”
1 1 0
- 0
â€”â€”â€”â€”â€”
1 1 0 0
- 1 1 0 0
â€”â€”â€”â€”â€”â€”â€”
0 0 0 0
```

Answer: `01010.1`

.

What does the `1`

to the right of the decimal point represent? Well, in the decimal number system, anything to the right of the decimal point represents a negative power of ten: `10`

, ^{-1}`10`

, and so on.^{-2}

As you may have guessed, in the binary number system, these are `2`

, ^{-1}`2`

, and so on. So ^{-2}`.1`

above really means `1(2`

, which is ^{-1})`1 / 2 = 0.5`

in decimal. And of course, the part in front of the decimal point evaluates to _{10}`10`

._{10}

That gives us `10`

. So our answer using binary long division is _{10} + 0.5_{10} = 10.5**exactly the same** as the one we got over in decimal!

### Integer Overflow and Underflow in Binary

What happens if you try to add one to the largest representable `N`

-bit signed integer?

For example, if `N = 32`

, weâ€™re really asking what happens if we try adding one to the largest representable `32`

-bit signed int.

Letâ€™s give it a shot:

```
0111...11111
+ 0000...00001
â€”â€”â€”â€”â€”â€”â€”â€”â€”â€”â€”â€”â€”â€”â€”â€”
```

In the rightmost column, weâ€™ll get `1`

, so thatâ€™s a zero carry a one. But as a result, all of the remaining additions will be _{2} + 1_{2} = 10_{2}`1`

since weâ€™ll always carry a one until we get to the leading bit:_{2} + 1_{2}

```
11111111111 <-- carry bits
0111...11111 (2^{N-1} - 1)
+ 0000...00001 (1)
â€”â€”â€”â€”â€”â€”â€”â€”â€”â€”â€”â€”â€”â€”â€”â€”
1000...00000 (-2^{N-1})
```

And what number is that in signed binary? Hmmâ€¦ Looks like itâ€™s the smallest representable negative number! What weâ€™ve observed here is called **integer overflow**. When you try to go past the largest representable signed integer in a given `N`

-bit system, the result *overflows* or *wraps around*.

What if we try to subtract one from the smallest representable `N`

-bit signed integer? First, weâ€™ll represent `-1`

as a signed integer in binary:_{10}

```
1 in binary: 0000...00001
Flipped: 1111...11110
Add one: 1111...11111 <-- -1
```

Now letâ€™s add this to the smallest representable signed integer:

```
1 <-- carry bits
1000...00000 (-2^{N-1})
+ 1111...11111 (-1)
â€”â€”â€”â€”â€”â€”â€”â€”â€”â€”â€”â€”â€”â€”â€”â€”
1|0111...11111 (2^{N-1} - 1)
```

Notice that the result carries an additional bit over, yielding a result that has `N+1`

bits. But our system only supports `N`

bits, so that leading `1`

is actually discarded. The result is the largest representable `N`

-bit signed integer, and this is known as **integer underflow**.

Overflow and underflow are things you should be mindful of in programs that are performing lots of computations, as you may end up getting unexpected results.

## The Binary Number System: Additional Topics for Exploration

That about does it for this introduction to the binary number system! We took a pretty in-depth look at decimal, binary, and hexadecimal, and I hope you now have a greater appreciation for the binary number system and the role that it plays in computing.

In reality, thereâ€™s much more to learn beyond what we covered here. If youâ€™re curious, I encourage you to look into representing floating point numbers in binary using the IEE754 format.

I hope you found this helpful! If you struggled with anything in particular, please let me know and Iâ€™ll try my best to help you out.

## đź’¬ Comments

Post comment