NUS HomeMaths
Home | Up


Last updated on: 10 November 2008 06:01:30 PM

Topics in this section is sorted alphabetically rather than in specific order. You may need to jump here to found what you need. Since item numbering here doesn't reflect anything and since this page will be expanded with more and more interesting mathematical facts, I decide not to put item numbers.

Materials here usually don't need sophisticated data structure or algorithm, but rather provides basic knowledge for subsequent chapters.

Base Number Conversion
Big Mod
Big Integer
Carmichael Number
Catalan Formula
Counting Combinations - C(N,K)
Divisors and Divisibility
Exponentiation
Factorial
Fibonacci

Greatest Common Divisor (GCD)
Lowest Common Multiple (LCM)
<math.h> - making the most of math library
Mathematical Expressions
Newton's Method
Prime Factors
Prime Numbers

Possible additions for this page:
-. Making the most of C/C++ math library
-. Chinese Remainder Theorem
-. Fermat Theorem, etc...

Base Number Conversion

Decimal is our most familiar base number, whereas computers are very familiar with binary numbers (octal and hexa too). The ability to convert between bases is important. Refer to mathematics book for this.


TEST YOUR BASE CONVERSION KNOWLEDGE

Solve UVa problems related with base conversion:

343 - What Base Is This?
353 - The Bases Are Loaded
389 - Basically Speaking

Big Mod

Modulo (remainder) is important arithmetic operation and almost every programming language provide this basic operation. However, basic modulo operation is not sufficient if we are interested in finding a modulo of a very big integer, which will be difficult and has tendency for overflow. Fortunately, we have a good formula here:

(A*B*C) mod N == ((A mod N) * (B mod N) * (C mod N)) mod N.

To convince you that this works, see the following example:

(7*11*23) mod 5 is 1; let's see the calculations step by step:

((7 mod 5) * (11 mod 5) * (23 mod 5)) Mod 5 =
((2 * 1 * 3) Mod 5) =
(6 Mod 5) = 1

Convinced? I hope you do. If no, then please refer to some proof in the internet. For now, just assume that this is true.

This formula is used in several algorithm such as in Fermat Little Test for primality testing:
R = B^P mod M (B^P is a very very big number). By using the formula, we can get the correct answer without being afraid of overflow.

This is how to calculate R quickly (using Divide & Conquer approach, see exponentiation below for more details):

long bigmod(long b,long p,long m) {
  if (p == 0)
    return 1;
  else if (p%2 == 0)
    return square(bigmod(b,p/2,m)) % m; // square(x) = x * x
  else
    return ((b % m) * bigmod(b,p-1,m)) % m;
}


TEST YOUR BIG MOD KNOWLEDGE

Solve UVa problems related with Big Mod:

374 - Big Mod
10229 - Modular Fibonacci - plus Fibonacci

Big Integer

Long time ago, 16-bit integer is sufficient: [-2^15 .. 2^15-1] ~ [-32.768 .. 32.767].

When 32-bit machines are getting popular, 32-bit integers become necessary. This data type can hold range from [-2^31 .. 2^31-1] ~ [2.147.483.648 .. 2.147.483.647]. Any integer with 9 or less digits can be safely computed using this data type. If you somehow must use the 10th digit, be careful of overflow...

But man is very greedy, 64-bit integers are created, referred as programmers as long long data type or Int64 data type. It has an awesome range up that can covers 18 digits integers fully, plus the 19th digit partially [-2^63 .. 2^63-1] ~ [9.223.372.036.854.775.808 .. 9.223.372.036.854.775.807]. Practically this data type is safe to compute most of standard arithmetic problems... except some problems...

Note: for those who don't know, in C, long long n is read using: scanf("%lld",&n); and unsigned long long n is read using: scanf("%llu",&n);

Now... RSA cryptography need 256 bits of number or more... This is necessary, human always want more security right? However, some problem setters in programming contests also follow this trend... Simple problem such as finding n'th factorial will become very very hard once the values exceed 64-bit integer data type... Yes, long double can store very high numbers, but it actually only stores first few digits and an exponent, long double is not precise.

In this case, you can't rely on standard data type and need to implement your own arbitrary precision arithmetic algorithm... Standard pen and pencil algorithm taught in elementary school will be your tool to implement basic arithmetic operations: addition, subtraction, multiplication and division. More sophisticated algorithm are available to enhance the speed of multiplication and division... Things are getting very complicated now...

Fortunately, there are several people who have actually implement these Big Integer library and willing to share the code with us. In Programming Challenges website, they offer one version, but here, I want to share with you Big Integer library by S. M. Mahbub Murshed Suman (udvranto at yahoo.com).

Please click the following links to download the library and a very basic sample code. Follow the comments given in the sample code to use the library.

The key feature of this library is its ability to override C++ basic operations, making life easier for us, programmers.

Example:

BigInteger n;
// try giving input: "1000000000000000000000000000000000000", this is more than 19 digits
cin >> n;
cout << n << endl; // output will be: "1000000000000000000000000000000000000"

I've used this library to solve many UVa problems. Try it.
 


TEST YOUR BIG INTEGER KNOWLEDGE

Solve UVa problems related with Big Integer:

485 - Pascal Triangle of Death
495 - Fibonacci Freeze - plus Fibonacci
10007 - Count the Trees - plus Catalan formula
10183 - How Many Fibs
- plus Fibonacci
10219 - Find the Ways !
- plus Catalan formula
10220 - I Love Big Numbers !
- plus Catalan formula
10303 - How Many Trees?
- plus Catalan formula
10334 - Ray Through Glasses
- plus Fibonacci
10519 - !!Really Strange!!
10579 - Fibonacci Numbers - plus Fibonacci


Any comments/bugs/suggestions, e-mail the author directly: (udvranto at yahoo.com).

Carmichael Number

Carmichael number is a number which is not prime but has >= 3 prime factors
You can compute them using prime number generator and prime factoring algorithm.

The first 15 Carmichael numbers are:
561,1105,1729,2465,2821,6601,8911,10585,15841,29341,41041,46657,52633,62745,63973

 


TEST YOUR CARMICHAEL NUMBER KNOWLEDGE

Solve UVa problems related with Carmichael Number:

10006 - Carmichael Number

Catalan Formula

The number of distinct binary trees can be generalized as Catalan formula, denoted as C(n).
For details, please refer to [CLR chapter 13].

C(n) = 2n C n / (n+1).

If you are asked values of several C(n), it may be a good choice to compute the values bottom up. Since C(n+1) can be expressed in C(n), as follows:

Catalan(n) =

      2n!
---------------
n! * n! * (n+1)

Catalan(n+1) =

           2*(n+1)
--------------------------- =
(n+1)! * (n+1)! * ((n+1)+1)

     (2n+2) * (2n+1) * 2n!
------------------------------- =
(n+1) * n! * (n+1) * n! * (n+2)

     (2n+2) * (2n+1) * 2n!
----------------------------------- =
(n+1) * (n+2) * n! * n! * (n+1)

(2n+2) * (2n+1)
--------------- * Catalan(n)
(n+1) * (n+2)
 


TEST YOUR CATALAN FORMULA KNOWLEDGE

Solve UVa problems related with Catalan Formula:

10007 - Count the Trees - * n! -> number of trees + its permutations
10303 - How Many Trees?

Counting Combinations - C(N,K)

C(N,K) means how many ways that N things can be taken K at a time.
This can be a great challenge when N and/or K become very large.

Combination of (N,K) is defined as:

     N!
----------
(N-K)!*K!

For your information, the exact value of 100! is:

93,326,215,443,944,152,681,699,238,856,266,700,490,715,968,264,381,621,
    468,592,963,895,217,599,993,229,915,608,941,463,976,156,518,286,253,
    697,920,827,223,758,251,185,210,916,864,000,000,000,000,000,000,000,000

so, how to compute the values of C(N,K) when N and/or K is big but the result is guaranteed to fit in 32-bit integer?

1. "Underflow" computation + Real number (sample code in Pascal)

var n,k,i:longint;
    R:real;

begin
  readln(n,k);
  R:=1;
  if (k>n-k) then k:=n-k; { use smaller k!!!, note C(10,6)==C(10,4) }
  for i:=1 to k do R:=R/i; { "underflow" multiplication }
  for i:=n downto n-k+1 do R:=R*i;
  writeln(round(R));
end.

2. Divide by GCD before multiply (sample code in C)

long gcd(long a,long b) {
  if (a%b==0) return b; else return gcd(b,a%b);
}

void Divbygcd(long& a,long& b) {
  long g=gcd(a,b);
  a/=g;
  b/=g;
}

long C(int n,int k){
  long numerator=1,denominator=1,toMul,toDiv,i;

  if (k>n/2) k=n-k; /* use smaller k */

  for (i=k;i;i--) {
    toMul=n-k+i;
    toDiv=i;
    Divbygcd(toMul,toDiv);       /* always divide before multiply */
    Divbygcd(numerator,toDiv);
    Divbygcd(toMul,denominator);
    numerator*=toMul;
    denominator*=toDiv;
  }

  return numerator/denominator;
}


TEST YOUR C(N,K) KNOWLEDGE

Solve UVa problems related with Combinations:

369 - Combinations
530 - Binomial Showdown

Divisors and Divisibility

If d is a divisor of n, then so is n/d, but d & n/d cannot both be greater than sqrt(n).

Example:

2 is a divisor of 6, so 6/2 = 3 is also a divisor of 6
(Simple isn't it, but it is very useful)

Let N = 25, Therefore no divisor will be greater than sqrt (25) = 5.
(Divisors of 25 is 1 & 5 only)

If you keep that rule in your mind, you can design an algorithm to find a divisor better, that's it, no divisor of a number can be greater than the square root of that particular number.

If a number N == a^i * b^j * ... * c^k then N has (i+1)*(j+1)*...*(k+1) divisors.

Example:

N = 60
60 = 2^2 * 3^1 * 5^1
Therefore 60 has (2+1)*(1+1)*(1+1) = 3*2*2=12 divisors
The divisors are: 1,2,3,4,5,6,10,12,15,20,30,60

There are many more interesting divisibility properties, these were found by mathematics people, who spent their time researching these properties... When I know more, I'll post it here.


TEST YOUR DIVISIBILITY KNOWLEDGE

Solve UVa problems related with Divisibility:

294 - Divisors

Exponentiation

(Assume pow() function in <math.h> doesn't exist...). Sometimes we want to do exponentiation or take a number to the power n. There are many ways to do that. The standard method is standard multiplication.

Standard multiplication

long exponent(long base,long power) {
  long i,result = 1;
  for (i=0; i<power; i++) result *= base;
  return result;
}

This is 'slow', especially when power is big - O(n) time. It's better to use divide & conquer.

Divide & Conquer exponentiation

You can express a^n in 2 ways:
a^n = (a^(n/2))^2 if n is even, or
a^n = a*a^(n-1)   if n is odd

Example:

Normal:
   2*2*2*2*2*2*2*2 ~~ 8 multiplications ~~ O(n).
Divide & Conquer:
   2^8 == (a^4)^2 == ((a^2)^2)^2 ~~ 3 multiplications ~~ O(log n).

Remember that O(log n) is much faster than O(n).

long square(long n) { return n*n; }

long fastexp(long base,long power) {
  if (power == 0)
    return 1;
  else if (power%2 == 0)
    return square(fastexp(base,power/2));
  else
    return base * (fastexp(base,power-1));
}

Using built in formula, a^n = exp(log(a)*n) or pow(a,n)

#include <stdio.h>
#include <math.h>

void main() {
  printf("%lf\n",exp(log(8.0)*1/3.0));
  printf("%lf\n",pow(8.0,1/3.0));
}

Both method produce the same answer. Fortunately, many compilers provide this exponent, natural logarithm, or power function in their math library. More interestingly, these mathematical formula is capable of handling fractions, as shown above:
8^(1/3) = cubicroot(8) = 2
This cannot be done using standard a^n = a*a*a..*a (n times)...

If you need integer result, just round the result, simple.


TEST YOUR EXPONENTIATION KNOWLEDGE

Solve UVa problems related with Exponentiation:

113 - Power of Cryptography

Factorial

Factorial is naturally defined as Fac(n) = n * Fac(n-1).

This is a recursive function. Fac function will always called itself until the base case. The base case for factorial is when n == 0. By mathematical definition, factorial of 0 is 1.

Example:

Fac(3) = 3 * Fac(2)
Fac(3) = 3 * 2 * Fac(1)
Fac(3) = 3 * 2 * 1 * Fac(0)
Fac(3) = 3 * 2 * 1 * 1
Fac(3) = 6

As you see, this leads into a series of postponed operations. Always try to avoid recursive function unless it's the only way to solve a problem. In this example, factorial can be written as iterative function, so use the iterative version instead.

Iterative version of factorial

long FacIter(int n) {
  int i,result = 1;
  for (i=2; i<=n; i++) result *= i; // index 'i' starts from 2 until n as 'result' starts from 1.
  return result;
}

So far, I reckon that this is the best algorithm to compute factorial... O(n).

Fibonacci

Fibonacci numbers was invented by Leonardo of Pisa (Fibonacci). He defined fibonacci numbers as a growing population of immortal rabbits. Series of Fibonacci numbers are: 1,1,2,3,5,8,13,21,...

To compute Fibonacci numbers directly, you can simply compute the closest integer of Ø^n / sqrt(5) where Ø (golden ratio) is ((1+sqrt(5))/2) ~~ 1.618. However this is not so accurate for big numbers.

Recurrence relation for Fib(n):

Fib(0) = 0
Fib(1) = 1
Fib(n) = Fib(n-1) + Fib(n-2)

If you implement Fibonacci using this method, you will create a tree recursion, it has an exponential growth and too slow.

Iterative version of Fibonacci (using Dynamic Programming)

int fib(int n) {
  int a=1,b=1,i,c;
  for (i=3; i<=n; i++) {
    c = a+b;
    a = b;
    b = c;
  }
  return a;
}

This algorithm runs in linear time O(n).

Quick method to quickly compute Fibonacci, using Matrix property.

   _       _ n       _            _
   |  0  1  |    =   |  fn-2  fn-1  |
   |_ 1  1 _|        |_ fn-1  f _|

I don't really understand the derivation, but this is the O(log n) code:

Divide_Conquer_Fib(n) {
  i = h = 1;
  j = k = 0;
  while (n > 0) {
    if (n%2 == 1) { // if n is odd
      t = j*h;
      j = i*h + j*k + t;
      i = i*k + t;
    }
    t = h*h;
    h = 2*k*h + t;
    k = k*k + t;
    n = (int) n/2;
  }
  return j;
}

This runs in O(log n) time.


TEST YOUR FIBONACCI KNOWLEDGE

Solve UVa problems related with Fibonacci:
Most of them need Big Integer library

495 - Fibonacci Freeze
10183 - How Many Fibs
10229 - Modular Fibonacci
10334 - Ray Through Glasses
10450 - World Cup Noise
10579 - Fibonacci Numbers

Greatest Common Divisor (GCD)

As it name suggest, Greatest Common Divisor (GCD) algorithm finds the greatest common divisor between two number a and b. GCD is a very useful technique, for example to reduce rational numbers into its smallest version (3/6 = 1/2).

The best GCD algorithm so far is Euclid's Algorithm. Euclid found this interesting mathematical equality. GCD(a,b) = GCD (b,(a mod b)). This algorithm is very effective and it's order of growth is an efficient O(log n).

Example: Compute GCD of 40 and 6

GCD(40,6) = GCD(6,4) = GCD(4, 2) = GCD(2,0) -> stop here, because one of the arguments is zero, the other argument that is not zero is the GCD.

Here is the fastest implementation of GCD algorithm (use int data type to make it faster if you know that you'll not using big numbers), using only 2 variables (see Swapping 2 values section) and change recursion into iteration.

int GCD(int a,int b) {
  while (b > 0) {
    a = a % b;
    a ^= b;
    b ^= a;
    a ^= b;
  }
  return a;
}

Later: Extended Euclid... (soon)

Lowest Common Multiple (LCM)

Lowest Common Multiple and Greatest Common Divisor (GCD) are two important number properties, and they are interrelated. Even though GCD is more often used than LCM, it is useful to learn LCM too.

LCM (m,n) = (m * n) / GCD (m,n)

Example:

LCM (3,2) = (3 * 2) / GCD (3,2)
LCM (3,2) = 6 / 1
LCM (3,2) = 6

Application of LCM -> to find a synchronization time between two traffic light, if traffic light A display green color every 3 minutes and traffic light B display green color every 2 minutes, then every 6 minutes, both traffic light will display green color at the same time.

Mathematical Expressions

There are three types of mathematical/algebraic expressions. They are Infix, Prefix, & Postfix expressions.

Infix expression grammar:
<infix> = <identifier> | <infix><operator><infix>
<operator> = + | - | * | /
<identifier> = a | b | .... | z

Infix expression example: (1 + 2) => 3, the operator is in the middle of two operands.
Infix expression is the normal way human compute numbers.

Prefix expression grammar:
<prefix> = <identifier> | <operator><prefix><prefix>
<operator> = + | - | * | /
<identifier> = a | b | .... | z

Prefix expression example: (+ 1 2) => (1 + 2) = 3, the operator is the first item.
One programming language that use this expression is Scheme language.
The benefit of prefix expression is it allows you write: (1 + 2 + 3 + 4)
like this (+ 1 2 3 4), this is simpler.

Postfix expression grammar:
<postfix> = <identifier> | <postfix><postfix><operator>
<operator> = + | - | * | /
<identifier> = a | b | .... | z

Postfix expression example: (1 2 +) => (1 + 2) = 3, the operator is the last item.

Postfix Calculator

Computer do postfix calculation better than infix calculation. Therefore when you compile your program, the compiler will convert your infix expressions (most programming language use infix) into postfix, the computer-friendly version.

Why do computer like Postfix better than Infix?

It's because computer use stack data structure, and postfix calculation can be done easily using stack.

Postfix calculation algorithm => Link to this file will be available later.

Infix to Postfix conversion

To use this very efficient Postfix calculation, we need to convert our Infix expression into Postfix. This is how we do it:

Example:

Infix statement: ( ( 4 - ( 1 + 2 * ( 6 / 3 ) - 5 ) ) )

This is what the algorithm will do, look carefully at the steps. Red colour is the character being analyzed.

Expression

Stack (bottom to top)

Postfix expression

((4-(1+2*(6/3)-5)))

(

 

((4-(1+2*(6/3)-5)))

((

 

((4-(1+2*(6/3)-5)))

((

4

((4-(1+2*(6/3)-5)))

((-

4

((4-(1+2*(6/3)-5)))

((-(

4

((4-(1+2*(6/3)-5)))

((-(

41

((4-(1+2*(6/3)-5)))

((-(+

41

((4-(1+2*(6/3)-5)))

((-(+

412

((4-(1+2*(6/3)-5)))

((-(+*

412

((4-(1+2*(6/3)-5)))

((-(+*(

412

((4-(1+2*(6/3)-5)))

((-(+*(

4126

((4-(1+2*(6/3)-5)))

((-(+*(/

4126

((4-(1+2*(6/3)-5)))

((-(+*(/

41263

((4-(1+2*(6/3)-5)))

((-(+*

41263/

((4-(1+2*(6/3)-5)))

((-(-

41263/*+

((4-(1+2*(6/3)-5)))

((-(-

41263/*+5

((4-(1+2*(6/3)-5)))

((-

41263/*+5-

((4-(1+2*(6/3)-5)))

(

41263/*+5--

((4-(1+2*(6/3)-5)))

 

41263/*+5--

 


TEST YOUR INFIX->POSTFIX KNOWLEDGE

Solve UVa problems related with postfix conversion:

727 - Equation

Newton's Method

Square roots

How computer calculate roots?, here is one of the method:

Guess

Quotient

Average

1

2/1

2

(2+1)/2

1.5

1.5

2/1.5

1.3333

(1.5+1.333)/2

1.4167

1.4167

2/1.4167

14118

(1.4167+1.4118)/2

1.4142

1.4142

...

...

...

...

We are using approximation in determining the square root of a given number X (in this case = 2), we start the guess with 1, then repeat the process until we get Y that is good enough (ie Y*Y - X = 0.001, if 0.001 is the precision that we want). Of course, better precision means more time to compute.

Cubic roots

How about cubic roots? Similar...

Guess

Y Value

New Y

1

(4/(1^2) + 2*1)/3

2

2

(4/(2^2) + 2*2)/3

1.6666

1.6666

(4/(1.6666^2) + 2*1.6666)/3

1.5911

1.5911

...

...

If Y is an approximation to the cube root of X, then the cube roots of X is given by the formula: (X/(Y^2) + 2*Y)/3. In above example, X = 8, and initial guess (Y) is 1.

Note that these methods are not precise...

Prime Factors

Definition: All integers can be expressed as a product of primes and these primes are called prime factors of that number.

Exceptions (My opinion):
For negative integers, multiply by -1 to make it positive again.
For -1,0, and 1, no prime factor... (by definition...)

Standard way

Generate a prime list again, and then check how many of those primes can divide n.

This is very slow. Maybe you can write a very efficient code using this algorithm, but there is another algorithm that is much more effective than this.

Restatement of Standard way

Check the factors first, and then test whether the factor is a prime or not.

This is one is slightly faster than standard way... sometimes restatement of an algorithm (viewing an algorithm from different side) can make it very different.

Creative way, using Number Theory

  1. Don't generate prime, or even checking for primality :-)

  2. Always use stop-at-sqrt technique

  3. Remember to check repetitive prime factors, example=20->2*2*5, don't count 2 twice. We want distinct primes (however, several problems actually require you to count these multiples..., so, please be careful)

  4. Make your program use constant memory space, no array needed.

  5. Use the definition of prime factors wisely, this is the key idea. A number can always be divided into a prime factor and another prime factor or another number. This is called the factorization tree.

Example:

    N
     \
    100
    /  \
   2   50
      /  \
     2   25
        /  \
       5    5
          /  \
         5    1

From this factorization tree, we can determine these following properties:

  1. If we take out a prime factor (F) from any number N, then the N will become smaller and smaller until it become 1, we stop here.

  2. This smaller N can be a prime factor or it can be another smaller number, we don't care, all we have to do is to repeat this process until N=1.

Further optimization is we can assume the factors are all odd (No even primes except for 2), second optimization is to stop when current factor is > sqrt (N). Here, we have to determine whether N has reached 1 or not, if N != 1, then N is prime too, then we have to add one more to our total prime factors.


TEST YOUR PRIME FACTORS KNOWLEDGE

Solve UVa problems related with prime factors:

583 - Prime Factors

Prime Numbers

Prime numbers are important in Computer Science (For example: Cryptography) and finding prime numbers in a given interval is a "tedious" task (for your computer, not for you :-). Usually, we are looking for big (very big) prime numbers therefore searching for a better prime numbers algorithms will never stop.

Many algorithms were created to find this prime numbers, each has different style, one is fast to code but slow when running, the other is difficult to code but can run in reasonable time.

However, the easiest method to find whether a given number is a prime or not is by testing it divisibility. If it can only be divided by 1 or by itself then it's prime. Of course, use efficient method!!!

Standard Divisibility Check / Trial Division (improved version):

This optimization trick was taken from USACO problem explanation for Super Prime Rib
Use optimized trial division for standard prime testing only. This algorithm is not fast enough for bigger number!!!

1. Standard prime testing

int is_prime(int n) {
  for (int i=2; i<=(int) sqrt(n); i++) if (n%i == 0) return 0;
  return 1;
}

This is extremely slow. A test that did no more than check the first 10,000 integers for primality ran for about 10.7 seconds on P90 machine. Here's the tester program:

void main() {
  int i,count=0;
  for (i=1; i<10000; i++) count += is_prime(i);
  printf("Total of %d primes\n",count);
}

2. Pull out the sqrt call

The first optimization was to pull the sqrt call out of the limit test, just in case the compiler wasn't optimizing that correctly, this one is faster:

int is_prime(int n) {
  long lim = (int) sqrt(n);
  for (int i=2; i<=lim; i++) if (n%i == 0) return 0;
  return 1;
}

3. Restatement of sqrt.

But you know what? You don't need to do that. You can just check to ensure i*i<n instead of i<sqrt(n). No significant execution time decrease, though. However, no floating point operations is usually a big win:

int is_prime(int n) {
  for (int i=2; i*i<=n; i++) if (n%i == 0) return 0;
  return 1;
}

4. We don't need to check even numbers

If you think about it, there's really no reason to try all those even numbers and check the divisibility property by jumping 2 numbers starting from 3 (That's it, check odd numbers only). You could do something like this and get another 20x speed improvement!!! It's pretty quick:

int is_prime(int n) {
  if (n == 1) return 0;         // 1 is NOT a prime
  if (n == 2) return 1;         // 2 is a prime
  if (n%2 == 0) return 0;       // NO prime is EVEN, except 2
  for (int i=3; i*i<=n; i+=2)   // start from 3, jump 2 numbers
    if (n%i == 0)               //  no need to check even numbers
      return 0;
  return 1;
}

5. Other prime properties

A (very) little bit of thought should tell you that no prime can end in 0,2,4,5,6, or 8, leaving only 1,3,7, and 9. It's fast & easy. Memorize this technique. It'll be very helpful for your programming assignments dealing with relatively small prime numbers (16-bit integer 1-32767). This divisibility check (step 1 to 5) will not be suitable for bigger numbers.

6. Divisibility check using smaller primes below sqrt(N):

Actually, we can improve divisibility check for bigger numbers. Further investigation concludes that a number N is a prime if and only if no primes below sqrt(N) can divide N.

Since this algorithm needs to know previous smaller primes, then this algorithm is more suitable for prime numbers generator, not prime tester.

How to do this:

  1. Create a large array. How large? here is the explanation

  2. Suppose max primes generated will not greater than 2^31-1 (2.147.483.647), maximum 32-bit integer.

  3. Since you need smaller primes below sqrt(N), you only need to store primes from 1 to sqrt(2^31)

  4. Quick calculation will show that of sqrt(2^31) = 46340.95.

  5. After some calculation, you'll find out that there will be at most 4792 primes in the range 1 to 46340.95. So you only need about array of size (roughly) 4800 elements.

  6. Generate that prime numbers from 1 to 46340.955. This will take time, but when you already have those 4792 primes in hand, you'll be able to use those values to determine whether a bigger number is a prime or not.

  7. Now you have 4792 first primes in hand. All you have to do next is to check whether a big number N a prime or not by dividing it with small primes up to sqrt(N). If you can find at least one small primes can divide N, then N is not prime, otherwise N is prime.

Fermat Little Test:

This is a probabilistic algorithm so you cannot guarantee the possibility of getting correct answer. In a range as big as 1-1000000, Fermat Little Test can be fooled by (only) 255 Carmichael numbers (numbers that can fool Fermat Little Test, see Carmichael numbers above). However, you can do multiple random checks to increase this probability.

Fermat Algorithm (don't ask me why, I don't know why this formula is like this):

If 2^N modulo N = 2 then N has a high probability to be a prime number.

Example:
let N=3 (we know that 3 is a prime).
2^3 mod 3 = 8 mod 3 = 2, then N has a high probability to be a prime number... and in fact, it is really prime.

Another example:
let N=11 (we know that 11 is a prime).
2^11 mod 11 = 2048 mod 11 = 2, then N has a high probability to be a prime number... again, this is also really prime.

This algorithm will be fast if you know how to do big exponentiation and modulo (again, use the big mod algorithm specified in this page). When N > 31, 2^N will exceed 2^31 (Maximum of 32-bit integer). However, this is not so easy, and according to my experience, bigger numbers tends to make Fermat Little Test produce a wrong answer. I myself don't really like this algorithm for programming contests since it's reliability is not guaranteed. You'll likely get Wrong Answer...

Sieve of Eratosthenes:

Sieve is the best prime generator algorithm. It will generate a list of primes very quickly, but it will need a very big memory. You can use Boolean flags to do this (Boolean is only 1 byte).

This is what Eratosthenes (from Greece) did thousand years ago:

He start with a list of numbers, excluding one because one is not a prime
2 3 4 5 6 7 8  9 10 11 12 13 14 15 16 17 18 19 20...

He preserve number 2 (red), but deletes all numbers that are multiples of 2 (blue).
2 3 4 5 6 7 8  9 10 11 12 13 14 15 16 17 18 19 20...

He continue to the next undeleted number 3 (red), but deletes all numbers that are multiples of 3 (blue), if it already deleted by previous checks (multiples of 2), he simply ignores it.
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20...

He continue to the next undeleted number 5 (red), but deletes all numbers that are multiples of 5 (blue), if it already deleted by previous checks (multiples of 3), he simply ignores it.
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20...

He do it again and again...until all has been marked.
2
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20...

This will be very fast, because you didn't do any division, multiplication, or modulo/remainder and you only need to strike out numbers from 2 till sqrt(N) because after that, all the non primes will have been deleted out by the multiples of previous values.

Algorithm for Sieve of Eratosthenes to find the prime numbers within a range L,U (inclusive), where must be L<=U.

void sieve(int L,int U) {
  int i,j,d;

  d=U-L+1; /* from range L to U, we have d=U-L+1 numbers. */
  /* use flag[i] to mark whether (L+i) is a prime number or not. */
  bool *flag=new bool[d];
  for (i=0;i<d;i++) flag[i]=true; /* default: mark all to be true */

  for (i=(L%2!=0);i<d;i+=2) flag[i]=false; /* mark even numbers as false */

  /* sieve by prime factors staring from 3 till sqrt(U) */
  for (i=3;i<=sqrt(U);i+=2) {
    if (i>L && !flag[i-L]) continue;

    /* choose the first number to be sieved -- >=L,
       divisible by i, and not i itself! */
    j=L/i*i;
    if (j<L) j+=i;
    if (j==i) j+=i; /* if j is a prime number, have to start form next one */

    /* now start sieving */
    j-=L; /* change j to the index representing j */
    for (;j<d;j+=i) flag[j]=false;
  }

  /* mark 1 as false, 2 as true */
  if (L<=1) flag[1-L]=false;
  if (L<=2) flag[2-L]=true;

  /* output the result */
  for (i=0;i<d;i++) if (flag[i]) cout << (L+i) << " ";
  cout << endl;
}

Solution from Zhang Kaicheng


TEST YOUR SIEVE OF ERATOSTHENES KNOWLEDGE

Solve UVa problems related prime & Sieve of Eratosthenes:

10140 - Prime Distance
10394 - Twin Primes

Popular Prime Numbers:

First prime and the only even prime: 2
Perfect prime: 7 (because I like 7 :-P)
In the range 1 to 100 : 25 primes
In the range 1 to 1000 : 168 primes
In the range 1 to 7919 : 1000 primes
In the range 1 to 10000 : 1229 primes
Largest prime in 32-bit integer range: 2^31 - 1 = 2.147.483.647

Funny stuff about Prime Numbers :-)

A "Theorem": All odd numbers is a prime
Taken from Prof Leong Hong Wai joke during CS1305 lecture.

Mathematician:
3 prime, 5 prime, 7 prime, 9 not prime... aha!!! Therefore this theorem is false.

Physicist:
3 prime, 5 prime, 7 prime, 9 OOPS experimental error, ignore this, 11 prime, 13 prime, this theorem is true

Engineer:
3 prime, 5 prime, 7 prime, 9 prime, 11 prime, 13 prime, hmm.. nothing wrong here, this theorem is true.

Computer Scientist:
3 prime, 5 prime, 7 prime, 7 prime, 7 prime, 7 prime, 7 prime, 7 prime (Infinite loop :-).

What's Next?

After reading this page, you should be able to handle many mathematical-related problems. There are much more harder mathematical-related problems that I can't solve, due to my poor math... However, I hope this page can give you something new to be learnt. Next, we are going to study two basic techniques in CS, Sorting and Searching. Stay tuned :D.


This document, 4_mathematics.html, has been accessed 19441 times since 02-Aug-04 14:13:06 SGT. This is the 5th time it has been accessed today.

A total of 10895 different hosts have accessed this document in the last 1587 days; your host, 38.103.63.56, has accessed it 2 times.

If you're interested, complete statistics for this document are also available, including breakdowns by top-level domain, host name, and date.