Number Theory

This section contains math that programmers end up dealing with often and explains how it works.

Division Remainder

I didn't introduce this on the basics page because most of the time people don't need it, but we'll find it useful in this chapter.

If you have something like $17/3$ it really means how many times number 3 fits into 17. It fits 5 times, but we have 2 left over because $5 \cdot 3 + 2 = 17$. This left-over part is the remainder, and it can be calculated with the % operator in most programming languages:

>>> 17 % 3
2

A common way to use this is to check whether an integer $a$ is divisible by another integer $b$. If it is, $a/b$ is an integer and a % b == 0:

>>> 15/3       # 15 is divisible by 3
5.0
>>> 15 % 3
0
>>> 14 / 3     # 14 is not divisible by 3
4.666666666666667
>>> 14 % 3
2

Prime Numbers

This section assumes that you know what square root is.

A prime number is a number that is divisible by only 1 and itself. For example, 6 is not a prime because it's divisible by 2 and 3, but 7 is a prime.

Many people new to programming write functions like this:

function isPrime(n) {
  if (n < 2) {
    return false;
  }
  for (var divisor = 2; divisor < n; divisor++) {
    if (n % divisor == 0) {
      return false;
    }
  }
  return true;
}

console.log(isPrime(17));     // true
console.log(isPrime(18));     // false

The code works, although it's kind of slow. But before we optimize it, I want to say a couple things:

Let's start by using the one and true way to debug.

for (var divisor = 2; divisor < n; divisor++) {
  console.log("divisor = %s, n / divisor = %s", divisor, n/divisor);
  ...
}

Here's the output:

divisor = 2, n / divisor = 8.5
divisor = 3, n / divisor = 5.666666666666667
divisor = 4, n / divisor = 4.25
divisor = 5, n / divisor = 3.4
divisor = 6, n / divisor = 2.8333333333333335
divisor = 7, n / divisor = 2.4285714285714284
divisor = 8, n / divisor = 2.125
divisor = 9, n / divisor = 1.8888888888888888
divisor = 10, n / divisor = 1.7
divisor = 11, n / divisor = 1.5454545454545454
divisor = 12, n / divisor = 1.4166666666666667
divisor = 13, n / divisor = 1.3076923076923077
divisor = 14, n / divisor = 1.2142857142857142
divisor = 15, n / divisor = 1.1333333333333333
divisor = 16, n / divisor = 1.0625
true

If $n$ is not a prime, we can write $n=ab$ where $a$ and $b$ are integers and at least one of them is 2 or bigger. If we assume that $a > \sqrt n$ and $b > \sqrt n$, we get this:

$$\begin{align}ab & > \sqrt n \sqrt n \\ ab & > n\end{align}$$

But we just said that $n=ab$ and this doesn't work. Our assumption was false and we know that $a \le \sqrt n$ or $b \le \sqrt n$. So if we check only numbers $\le \sqrt n$, we'll find $a$ or $b$:

for (var divisor = 2; divisor <= Math.sqrt(n); divisor++) {
  ...
}

Now we get much less output than before, but the code still works.

divisor = 2, n / divisor = 8.5
divisor = 3, n / divisor = 5.666666666666667
divisor = 4, n / divisor = 4.25
true

The code is a bit messier if your favorite programming language doesn't support C-style for loops. For example, Python's int(math.sqrt(n)) returns the smallest integer that is $\le \sqrt n$, and range(a, b) doesn't go all the way to b so we also need a +1. We need an integer because range doesn't like floats.

for divisor in range(2, int(math.sqrt(n))+1):
    ...

We can take a step further and optimize more because all non-primes consist of primes multiplied with each other. For example:

$$\begin{align}1050 = 2 \cdot 3 \cdot 5 \cdot 5 \cdot 7\end{align}$$

So it would be enough to check for divisibility with just primes. For example, $\sqrt{123} \approx 11.0905$ and primes $\le 11$ are 2, 3, 5, 7 and 11, so if 123 is not a prime then it's divisible by one of these numbers.

From a programming point of view, this would mean generating a list of primes and looping over that. That's probably not worth the effort, but we can do a little better than checking for divisibility with everything. All even numbers are divisible by 2 and thus not prime, so we can do this:

for (var divisor = 2; divisor <= Math.sqrt(n); divisor += (divisor==2 ? 1 : 2)) {
  ...
}

The code is kind of messy, but divisor gets the values $2,3,5,7,9,11,...$ like we wanted it to get.

Here's the even messier Python equivalent:

if n == 2:
    return True
for divisor in itertools.chain([2], range(3, int(math.sqrt(n))+1, 2)):
    ...

If n == 2, we must not check for divisibility with 2 because 2 % 2 == 0 even though 2 is prime, and unlike the JavaScript thing, the Python mess always checks for divisibility by 2.

So, here are our final prime checking examples for JavaScript and Python:

function isPrime(n) {
  if (n < 2) {
    return false;
  }
  for (var divisor = 2; divisor <= Math.sqrt(n); divisor += (divisor==2 ? 1 : 2)) {
    if (n % divisor == 0) {
      return false;
    }
  }
  return true;
}

import itertools
import math

def isprime(n):
    if n < 2:
        return False
    if n == 2:
        return True

    for divisor in itertools.chain([2], range(3, int(math.sqrt(n))+1, 2)):
        if n % divisor == 0:
            return False
    return True

Exercise

Translate different isprime() functions to your favorite programming language and measure how fast they run. Try to optimize them if the results are not as good as you expected them to be.

Hexadecimal Colors

You might have seen weird colors before, like #ff0000 is somehow magically red or #0000ff is blue. This section is all about what the heck happens in this color notation.

Let's start with an example. If we have a number like 2017, it really means this:

$$\begin{align}2017 &= 2 \cdot 1000 + 0 \cdot 100 + 1 \cdot 10 + 7 \\ &= 2 \cdot 10^3 + 0 \cdot 10^2 + 1 \cdot 10^1 + 7 \cdot 10^0\end{align}$$

Here $10^0 = 1$; see this thing for details.

The idea with hexadecimal is that instead of using 10 as a magic number we use 16. That's why hexadecimal is also called base 16. But the problem is that we only have 10 digits, 0 to 9, so we borrow a few letters so that A=10, B=11, C=12, D=13, E=14 and F=15. For example:

$$\begin{align}\text{0xCAFE} &= \text{0xC} \cdot 16^3 + \text{0xA} \cdot 16^2 + \text{0xF} \cdot 16^1 + \text{0xE} \cdot 16^0 \\ &= 12 \cdot 16^3 + 10 \cdot 16^2 + 15 \cdot 16 + 14 \\ &= 51966\end{align}$$

Here $\text{0x}$ means heXadecimal. Note that the first character is a zero, not the letter O. Mathematicians don't use this $\text{0x}$ notation, but I used it here because it's very common in programming.

The sane way to calculate the last step is to use a programming interpreter or calculator of your choice. Don't try to do it by hand.

Most programming languages have very good support for hexadecimal and a few other bases. For example, here's Python:

>>> 0xcafe
51966
>>> 0xc * 16**3 + 0xa * 16**2 + 0xf * 16 + 0xe
51966
>>> 12 * 16**3 + 10 * 16**2 + 15 * 16 + 14
51966
>>> hex(51966)
'0xcafe'
>>> int('cafe', 16)
51966
>>> 'i went to a %x' % 51966
'i went to a cafe'
>>> 'i went to a {:x}'.format(51966)
'i went to a cafe'

See Also

As you can see, it's possible to represent some words with hexadecimal numbers. There's a nice list of funny hexadecimal numbers that are actually being used on Wikipedia.

Now let's have a look at the colors. Another common way to represent colors is rgb(R,G,B) where R, G and B are red, green and blue values between 0 and 255. For example, rgb(255,0,0) is red because the red value is at maximum and other values are 0. rgb(0,0,0) is black and rgb(255,255,255) is white.

You might have noticed that $0=\text{0x0}$ and $255 = 15 \cdot 16 + 15 = \text{0xFF}$, and that's not just a random coincidence. A color like #RRGGBB is actually rgb(RR,GG,BB) where RR, GG and BB are hexadecimal. For example, #ff0000 = rgb(0xff,0x00,0x00) = rgb(255,0,0).

These Python functions convert RGB colors to hexadecimal and back:

def hex2rgb(hexcolor):
    assert len(hexcolor) == 7 and hexcolor[0] == '#'
    return (int(hexcolor[1:3], 16), int(hexcolor[3:5], 16), int(hexcolor[5:7], 16))

def rgb2hex(r, g, b):
    # string formatting magic: %02x means hexadecimal padded with
    # zeros until it's at least 2 characters wide
    return '#%02x%02x%02x' % (r, g, b)

Here's a usage example:

>>> hex2rgb('#ff00ff')
(255, 0, 255)
>>> rgb2hex(255, 0, 255)
'#ff00ff'

Note that most color parsers support specifying colors so that e.g. #f0f and #fff000fff are equivalent to #ff00ff, but the above program doesn't support that.