The sequence of Fibonacci numbers Fi is defined as follows: F1 = 1, F2 = 1, and Fi = Fi-1 + Fi-2 for all i ≥ 3. So the sequence is
1, 1, 2, 3, 5, 8, 13, 21, …
Let's write a program that reads an integer N and writes the first N numbers in the Fibonacci sequence.
To accomplish this, we use two integer variables a
and b
to store the next two numbers that we will
output:
var a: integer = 1; b: integer = 1; c: integer; n, i: integer; begin readln(n); for i := 1 to n do begin write(a, ' '); c := a + b; a := b; b := c; end; writeln; end;
On each loop iteration, we first output a
. We then
compute c
, which is the Fibonacci number that comes
after a
and b
. Then, since we have already
output a
, we shift b
into a
and then c
into b
.
The key to solving a problem like this is figuring out what state
we must remember between loop iterations – in this case, the
variables a
and b
.
In an earlier lecture we saw how to write a program that reads a series of integers and prints the largest of them. Now let's write a program that prints the second largest of a series of input numbers.
We can achieve this by using two variables to remember the largest and second largest numbers that we've seen so far:
var max: integer = - MaxInt; // largest so far max2: integer = - MaxInt; // second largest so far i: integer; begin while not seekEof do begin readln(i); if i > max then // i is the largest so far begin max2 := max; max := i; end else if i > max2 then // i is the second largest so far max2 := i; end; writeln(max2); end;
Study the program to understand how it works.
Again, the key to solving this problem is figuring out what state we
must keep between iterations – in this case, the variables max
and max2
.
Also note that the program above allows the
largest and second largest numbers to be the same. For example, if
the input is the numbers 6, 6, 4, and 4, then the program will write
6. If we don't want this, we can change the else
statement above to
else if (i <> max) and (i > max2) then
With this change, if the program sees the current maximum value again then it will ignore it. With the input numbers 6, 6, 4, and 4, the program will print 4.
We can use math to break a decimal number into digits. Suppose that n = 6437. Then
n mod 10 = 7
n div 10 = 643
In other words, (n mod 10) gives us the last digit of n. (n div 10) gives us all digits except the last.
Using this idea, we can build a loop that iterates over the digits of n. Here's a program to compute the sum of the digits in a number:
var n: integer; sum: integer = 0; begin readln(n); while n > 0 do begin sum := sum + (n mod 10); n := n div 10; end; writeln(sum); end;
In the number n = 6437, 6 is the most significant digit and 7 is the least significant digit. In the program above we can see that it's easy to iterate over the digits from least significant to most significant. (It is also possible, but not quite as easy, to go in the other direction.)
Also note that
n mod 100 = 37
n div 100 = 64
So by using a higher power of 10 such as 100 = 102, we can chop off more digits at once.
(Finally, note that the above techniques work in any base, not just base 10. We will begin working with other bases soon.)
Similarly, we can use math to construct a number from a set of decimal digits. If n = 6437, then
10 ⋅ n = 64370
10 ⋅ n + 5 = 64375
So we can append the digit d to n by computing (10 ⋅ n + d).
Using this idea, we can build a loop that constructs a number containing the digits 1 through n:
var digits, i: integer; n: integer = 0; begin readln(digits); for i := 1 to digits do n := 10 * n + i; writeln(n); end;
We see here that it's easy to build a number from one digit at a time, starting with the most significant digit. (It is also possible, but not quite as easy, to go in the other direction.)
(Once again, this will work in any base, not just base 10.)
The length
method returns the number of (8-bit)
characters in a string:
var s: string; begin s := 'watermelon'; writeln(length(s)); // writes 10 end.
We can use the []
operator to extract individual
characters from a string. String characters are always indexed from
1, so in the above string the characters have indices 1 through 10:
var s: string = 'watermelon'; begin writeln(s[1]); // writes 'w' writeln(s[6]); // writes 'm' end.
Note that any non-ASCII characters in a string are represented using
multiple bytes. Be aware that length
and the []
operator will behave differently if a string has such characters:
var s: string = 'řehoř'; begin writeln(length(s)); // writes 7 writeln(s[3]); // writes 'e', since 'ř' occupies both s[1] and s[2] end.
But in this course we will generally work with strings containing only ASCII text.
We can use a loop to iterate over the characters in a string. Here's a program to count the number of occurrences of the letter 'x' in a string:
var s: string; i: integer; count: integer = 0; begin readln(s); for i := 1 to length(s) do if s[i] = 'x' then count := count + 1; writeln(count); end.
A palindrome is a string that reads the same forwards and backwards, such as "racecar". Here's a program to check whether a string is a palindrome:
var s: string; i: integer; begin readln(s); for i := 1 to length(s) div 2 do if s[i] <> s[length(s) + 1 - i] then begin writeln('not a palindrome'); exit; end; writeln('palindrome'); end.
Strings in Pascal are mutable: they can change. We can update individual characters in a string like this:
var s: string = 'dime'; begin s[1] := 'l'; // now s = 'lime' s[3] := 'n'; // now s = 'line' end.
What will happen if we try to access string characters that are out of bounds? For example:
var s: string = 'cantelope'; begin write(s[100]); // out of bounds s[200] := 'x'; // out of bounds end.
The above accesses are out of bounds because length(s) = 9, so the only valid indices are 1 through 9.
By default, Pascal will not detect the above range errors. The read of s[100] will return some arbitrary value. The write to s[200] is worse: it will write to some area of memory that is outside the string. This unsafe behavior will have unpredictable effects: it might corrupt other variables in the program or cause the program to crash.
Fortunately we can ask Pascal to turn on range checking, which will check that each string access is in bounds. To do so, include the following at the top of your program:
{$r+}
With range checking enabled, if we run the above program we will see
Runtime error 201 at $0000000000400E1D $0000000000400E1D $000000000040018C
I strongly suggest that you enable range checking in all programs. If your program has a range error bug, generally you want to learn about it immediately.
As we saw above, a string holds a set of characters that we can access individually by index. An array generalizes this concept: it is a set of values of some type T that we can we access individually by index.
Arrays in Pascal come in two forms: static and dynamic. A static array has a fixed size, whereas a dynamic array can grow and shrink as the program runs.
You can declare a static array like this:
var a: array[1..100] of integer;
The array indices don't need to begin with 1. They can start at 0 or any other value:
var a: array[0..49] of boolean;
The length
function returns the total number of elements
in an array. Also, the built-in functions low
and high
return an array's lowest and highest index values, respectively:
var a: array[0..49] of float; begin writeln(length(a)); // writes 50 writeln(low(a)); // writes 0 writeln(high(a)); // writes 49 end.
Here is a program that reads 10 integers from standard input and then writes them out in reverse order, using a static array:
var a: array[1..10] of integer; i: integer; begin for i := 1 to 10 do readln(a[i]); for i := 10 downto 1 do writeln(a[i]); end.
Of course, it would be nice if our program were more flexible and could handle any number of integers, not just 10. We can achieve this using a dynamic array. You can declare a dynamic array like this:
var a: array of integer;
Before you can use a dynamic array, you must set its length by
calling setLength
:
setLength(a, 100);
Dynamic arrays are always indexed from 0, so after the call above the array will hold values with indices from 0 to 99.
You can call setLength
many times on the same array to grow or shrink it as you like. When
growing a dynamic array, setLength
sets any newly allocated elements to zero.
Let's rewrite the program above so that it can handle any number of integers. We'll assume that the first line of the input contains a number N indicating how many values will follow. After the program reads them all, it will print them in reverse order:
var a: array of integer; n, i: integer; begin readln(n); // number of elements; setLength(a, n); for i := 0 to n - 1 do readln(a[i]); for i := n - 1 downto 0 do writeln(a[i]); end.
Let's make one more improvement to our program. The input will no longer begin with the count N. Instead, we will simply read as many numbers as are available until the end of the input is reached (i.e. the user has pressed Ctrl+D or Ctrl+Z). To do this, we will need to grow the dynamic array as we add each number:
var a: array of integer; i: integer; begin setLength(a, 0); while not seekEof do begin setLength(a, length(a) + 1); readln(a[high(a)]); end; for i := high(a) downto 0 do writeln(a[i]); end.
Let's write a program that lets the user enter a date given by a month and day. The program will print out that date's day number with the year, where
January 1 = day 1
January 2 = day 2
…
January 31 = day 31
February 1 = day 32
February 2 = day 33
…
December 30 = day 364
December 31 = day 365
We assume that the year in question is not a leap year, so February has 28 days.
For example:
enter month and day: 2 5 day of year: 36 === enter month and day: 12 30 day of year: 364
To write this program, it will be helpful to have an array containing the number of days in each month of the year. In Pascal we may specify a set of initial values to be stored in a static array. In our program, this array is a constant:
const Days: array[1..12] of integer = (31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31); var month, day, i: integer; total: integer = 0; begin write('enter month and day: '); readln(month, day); for i := 1 to month - 1 do total := total + Days[i]; total := total + day; writeln('day of year: ', total); end;
In the last lecture we learned an algorithm for determining whether an integer is prime. We will now study another number-theoretic algorithm, namely for determing an integer's prime factorization.
The Fundamental Theorem of Arithmetic states that
Every positive integer has a unique prime factorization.
For example:
24 = 2 ⋅ 2 ⋅ 2 ⋅ 3 = 23 ⋅ 31
30 = 2 ⋅ 3 ⋅ 5 = 21 ⋅ 31 ⋅ 51
64 = 2 ⋅ 2 ⋅ 2 ⋅ 2 ⋅ 2 ⋅ 2 = 26
100 = 2 ⋅ 2 ⋅ 5 ⋅ 5 = 22 ⋅ 52
We can use trial division to factor an integer. This is similar to our primality testing algorithm, which also used trial division. Given an integer N, we first try dividing N by 2, then by 3 and so on. If n is actually divisible by a number such as 3, then we must repeatedly attempt to divide by that same number. since the same prime factor may appear multiple times in the factorization.
Here is a first program for prime factorization:
var n: integer; i: integer; begin write('number to factor: '); readln(n); i := 2; while n > 1 do if n mod i = 0 then begin write(i, ' '); n := n div i; end else i := i + 1; end.
Study the program to understand how it works. Note that the program
will attempt to divide by non-prime factors, such as when i = 4. But
n will never be divisible by such values. That's because any
non-prime factor i
is itself the product of two (or
more) smaller primes, and we have already divided those primes out of
n
, so n
cannot possibly be divisible by i
.
The program works, but is inefficient because it potentially tests
all values from 1 to n. Just as in our primarily testing algorithm,
we can make the program much more efficient by stopping our loop once
i
reaches sqrt(n).
We can see that this is valid using the same argument as in the last lecture. Once again, if ab = n for integers a and b, then we must have either a ≤ sqrt(n) or b ≤ sqrt(n). Proof: Suppose that a > sqrt(n) and b > sqrt(n). Then ab > sqrt(n) ⋅ sqrt(n) = n, a contradiction. So either a ≤ sqrt(n) or b ≤ sqrt(n).
It follows that if we have tested all the values from 2 through sqrt(n) and none of them divide n, then if ab = n we must have a = 1 or b = 1. And so n must be prime. Therefore we can end the loop and simply print n itself, which must be the last prime factor.
Here is the updated program:
var n: integer; i: integer; begin write('number to factor: '); readln(n); i := 2; while i * i <= n do // i <= sqrt(n) if n mod i = 0 then begin write(i, ' '); n := n div i; end else i := i + 1; writeln(n); end.
Note that in this program the while
condition can be
either 'i * i <= n
' or 'i <= sqrt(n)
'.
These are equivalent, but the first version is a bit more efficient
since it uses integer rather than floating-point arithmetic.
Here is a program to capitalize all words in a string. Here, a word is a sequence of non-space characters.
var s: string; prev: char; i: integer; begin readln(s); prev := ' '; for i := 1 to length(s) do begin if (prev = ' ') and (s[i] <> ' ') then s[i] := upCase(s[i]); prev := s[i]; end; writeln(s); end.
Here's a program to find the most frequent letter in its input, We ignore case: 'a' and 'A' are considered to be the same letter. The program prints the most frequent letter along with a count of its occurrences.
The program works by computing a histogram of letter
frequencies. We use the fact that in Pascal array
indices may even be characters! Furthermore we can even use a for
loop to loop over a range of characters.
uses character; // for 'isLetter' function var count: array['a' .. 'z'] of integer; c: char; m: char; begin for c := 'a' to 'z' do count[c] := 0; while not eof do begin read(c); c := lowerCase(c); if isLetter(c) then count[c] := count[c] + 1; end; m := 'a'; // most frequent letter so far for c := 'b' to 'z' do if count[c] > count[m] then m := c; writeln(m, ' ', count[m]); end.
We all remember from geometry that if a and b are the lengths of the legs of a right triangle, and c is the length of the hypotenuse, then
a2 + b2 = c2
In some such triangles a, b, and c are all integers. For example:
32 + 42 = 52
52 + 122 = 132
We'd now like to write a program that finds all sets of integers (a, b, c) with 1 ≤ a < b < c ≤ 100 such that a2 + b2 = c2.
We will accomplish this via exhaustive search: we simply try all possible triples (a, b, c) to see which ones satisfy the equation a2 + b2 = c2. We can use a triple for loop:
var a, b, c: integer; begin for a := 1 to 100 do for b := a + 1 to 100 do for c := b + 1 to 100 do if a * a + b * b = c * c then writeln('a = ', a, ', b = ', b, ', c = ', c); end;
The output is
a = 3, b = 4, c = 5 a = 5, b = 12, c = 13 a = 6, b = 8, c = 10 a = 7, b = 24, c = 25 …