Useful Math

AKA. Putting discrete math to good use.

Created by Tyler Burnham

Prime Numbers

What are prime numbers?

A natural number greater then one with no positive divisors other then one and itself.
First 25 Primes: (2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47,53, 59, 61, 67, 71, 73, 79, 83, 97, 101)

Checking if a number is prime


def check_prime(prime):
    num = 2
    while num < (prime/2):
        if(prime%num == 0):
            return False
        num += 1
    return True
					

Sieve of Eratosthenes

Sieve of Eratosthenes


def primes_upto(limit):
    is_prime = [False] * 2 + [True] * (limit - 1) 
    for n in range(int(limit**0.5 + 1.5)): # stop at ``sqrt(limit)``
        if is_prime[n]:
            for i in range(n*n, limit+1, n):
                is_prime[i] = False
    return [i for i, prime in enumerate(is_prime) if prime]
                        

Sieve of Eratosthenes Breakdown


>>> is_prime = [False] * 2 + [True] * (10 - 1)
[False, False, True, True, True, True, True, True, True, True, True]

>>> for n in range(int(10**0.5 + 1.5)): # stop at ``sqrt(limit)``
    print(n)   
0
1
2
3

>>> for i in range(2*2, 10+1, 2):
    print(i)  
4
6
8
10
                        

Formatting Numbers

Python


print("{0}".format(1)) # Place a value into a string, using a placeholder

print("{0:.4f} {1:.2f}".format(1, 2)) # Prints "1.0000 2.00"

print("Address {0:x} and {1:X}".format(255, 234)) # prints "Address ff and EA"

print("{0:04x}".format(255)) # prints "00ff" (padding is great!)
                        

Java


public class Format {
    public static void main(String[] args) {
        System.out.printf("%.4f %.2f\n", 1.0, 2.0); // note the values are NOT integers

        System.out.printf("%x %X\n", 255, 234);

        System.out.printf("%04x\n", 255);
     }
 }
                        

Bases and Number Representation

How do you write a number

Consider the number "1362". breaking it down by "places" gives

  • 1 "thousand"
  • 3 "hundreds"
  • 6 "tens"
  • 2 "ones"

Another Way to Write It

1362 can be written as $1(10^3) + 3(10^2) + 6(10^1) + 2(10^0)$. More generically, if the $k$th digit is $d_k$, we now have a number written as

\[ n = \sum_{k=0}^n d_k 10^k \]

But Why 10?

In fact, we choose any arbitrary base $b$, instead of 10:

\[ n = \sum_{k=0}^n d_k b^k \]

So can we convert between bases?

Converting Between Bases (Part 1: Extracting Digits)

Let's say we have a number $N$, and we want to extra the $k$th digit in base $b$:

If you strip the decimal from $N / (b^k)$, you remove digits below the $k$th digit

If you take modulus (the % operator), of that, you drop the upper digits. So:

\[ d_k = \lfloor \frac{N} {b ^ k} \rfloor \mod b \]

Converting Between Bases (Part 2: How Many Digits)

If there are $D$ digits for the number $N$ in base $b$, then the largest digit will be written as $N = d_D b^D + \ldots$. We can extract $D$ via the logarithm (prove this yourself):

\[ D = \log_b{N} = \frac{\log{N}}{\log{b}} \]

Putting it together in Python


import math

def extract_digit(number, base, digit):
    return math.floor(number / (base ** digit)) % base

def number_of_digits(number, base):
    return math.ceil(math.log(number, base))

def convert_to_base(number, base):
    digits = number_of_digits(number, base)
    converted = ''
    for k in range(digits):
        converted = str(extract_digit(number, base, k)) + converted
    return converted

print(convert_to_base(236, 2))
print(bin(236))
                        

Caveat!

For bases over 10, extract_base will return a number over 10 (a two digit number), so you'll have to provide a mapping for digits...

How Computers Represent Numbers

Binary

  • Numbers are represented as a series of bits:
    10110101011100000
  • Each position corresponds to whether or not the corresponding power of two is included in the number
  • Example
    1011
    means that $2^0$, $2^1$ and $2^3$ are present in the number. This means the number is $2^0 + 2^1 + 2^3 = 1 + 2 + 8 = 11$ in base 10.
  • This is sometimes written as $1011_2 = 11_{10}$

Negative Numbers and Overflow

  • In order to store the sign of a number, computers generally reserve the first bit for sign. If this bit is `0`, then the number is positive. If it's `1` the number is negative. This representation is called Two's Complement.
  • Because numbers are fixed size in C and Java, that means there is a point where the number will max out and wrap around to the negatives!

Wrap Around Example (in C)


#include

int main(void) {
    // we're going to keep doubling this number and print it as we go
    int N = 1;

    int i;

    for(i = 0; i < 50; i++) {
        // double the number
        N *= 2;

        // print i and our number out (using printf)
        printf("i = %d", i);
        printf(" N  = %d\n", N);
    }
}
                        

For more help see:

The Output


i = 0 N  = 2
i = 1 N  = 4
i = 2 N  = 8
i = 3 N  = 16
i = 4 N  = 32
i = 5 N  = 64
i = 6 N  = 128
i = 7 N  = 256
i = 8 N  = 512
i = 9 N  = 1024
i = 10 N  = 2048
i = 11 N  = 4096
i = 12 N  = 8192
i = 13 N  = 16384
i = 14 N  = 32768
i = 15 N  = 65536
i = 16 N  = 131072
i = 17 N  = 262144
i = 18 N  = 524288
i = 19 N  = 1048576
i = 20 N  = 2097152
i = 21 N  = 4194304
i = 22 N  = 8388608
i = 23 N  = 16777216
i = 24 N  = 33554432
i = 25 N  = 67108864
i = 26 N  = 134217728
i = 27 N  = 268435456
i = 28 N  = 536870912
i = 29 N  = 1073741824
i = 30 N  = -2147483648
i = 31 N  = 0
i = 32 N  = 0
...
                        

Same Example in Python


N = 1
for i in range(50):
    N *= 2

    print("i = {0} N = {1}".format(i, N))
                        

Output


i = 0 N = 2
i = 1 N = 4
i = 2 N = 8
i = 3 N = 16
i = 4 N = 32
i = 5 N = 64
i = 6 N = 128
i = 7 N = 256
i = 8 N = 512
i = 9 N = 1024
i = 10 N = 2048
i = 11 N = 4096
i = 12 N = 8192
i = 13 N = 16384
i = 14 N = 32768
i = 15 N = 65536
i = 16 N = 131072
i = 17 N = 262144
i = 18 N = 524288
i = 19 N = 1048576
i = 20 N = 2097152
i = 21 N = 4194304
i = 22 N = 8388608
i = 23 N = 16777216
i = 24 N = 33554432
i = 25 N = 67108864
i = 26 N = 134217728
i = 27 N = 268435456
i = 28 N = 536870912
i = 29 N = 1073741824
i = 30 N = 2147483648
i = 31 N = 4294967296
i = 32 N = 8589934592
i = 33 N = 17179869184
i = 34 N = 34359738368
i = 35 N = 68719476736
i = 36 N = 137438953472
i = 37 N = 274877906944
i = 38 N = 549755813888
i = 39 N = 1099511627776
i = 40 N = 2199023255552
i = 41 N = 4398046511104
i = 42 N = 8796093022208
i = 43 N = 17592186044416
i = 44 N = 35184372088832
i = 45 N = 70368744177664
i = 46 N = 140737488355328
i = 47 N = 281474976710656
i = 48 N = 562949953421312
i = 49 N = 1125899906842624
                        

What's the Lesson here?

  • Pay attention to the problem inputs/range of values you could potentially receive
  • Choose a `long` when necessary
  • Python does this for you under the hood! In fact, integers are arbitrary precision!
  • If you need this behavior in Java, check out BigInteger

Greatest Common Divisor

Euclidean Algorithm

Python

                    
import fractions
print(fractions.gcd(20,8))

Note: In python 3.5 use math.gcd(a,b)

Java

                                       
private static int gcdFunction(int a, int b) {
    BigInteger b1 = BigInteger.valueOf(a);
    BigInteger b2 = BigInteger.valueOf(b);
    BigInteger gcd = b1.gcd(b2);
    return gcd.intValue();
}
Source

Least Common Multiple

LCM

The smallest number that evenly divides two numbers.

\[ lcm(a,b) = \frac{ab}{gcd(a,b)} \]

Python

                    
def lcm(a,b):
    return b*a/fractions.gcd(b,a)
print(lcm(20,8)) #returns 40

Fractions and Complex Numbers

Python Fraction Class

               
>>> from fractions import Fraction
>>> x = Fraction(3,4)
>>> y = Fraction(5,6)
>>> x+y
Fraction(19, 12)
>>> x*y
Fraction(5, 8)
>>> x-y
Fraction(-1, 12)
>>> x/y
Fraction(9, 10)
>>> int(x+y)
1
>>> float(x+y)
1.5833333333333333

Python Complex Math

 
>>> z = 2+3j
>>> z.real
2.0
>>> z.imag
3.0
>>> z.conjugate()
(2-3j)
 
>>> abs(3 + 4j)
5.0
>>> pow(3 + 4j, 2)
(-7+24j)
 
>>> import cmath
>>> cmath.sin(2 + 3j)
(9.15449914691143-4.168906959966565j)