Composing Functions

Let's suppose that I had the function max defined as

int max(int a, int b)
{
  return (b > a) ? b : a;
}
but that my program had three ints, x, y and z, amongst which I need the largest. Were I to write
max(x,y,z)
the compiler would complain ... the only max function it knows about only takes two arguments! However, I could say the following:
max(max(x,y),z)
This is our first example of composition of functions. When the function max gets called, its two argument expressions are evaluated. The first is max(x,y), which evaluates to the larger of the two values, and the second is simply z. So, what we get out of this is the maximum of all three values.

The most important thing I can tell you about composing functions, is that there is really nothing to talk about. Function arguments are given in your code by expressions, right? And those expressions are evaluated before calling the function to produce the argument objects that are passed to the function. So, whether or not the argument expressions themselves contain function calls is immaterial — the system works the same.

The rand() Function

Quite often in programming you need random numbers. How this is done is a science in and of itself, but the standard library cstdlib contains a function rand() that you can use. It returns a random int in the range 0,....,RAND_MAX, where RAND_MAX is a variable defined in cstdlib. So, if you need to print out 10 random numbers in the range [0,1], you could do the following:
    
for(int i = 0; i < 10; i++)
  cout << double(rand())/RAND_MAX << " ";
cout << endl;
If I run this, I get:

0.513871 0.175726 0.308634 0.534532 0.94763 0.171728 0.702231 0.226417 0.494766 0.124699
Unfortunately, if I run it again, I get the same sequence of numbers! As a matter of fact, every time I run it, I get the same 10 "random" numbers! The problem is this, the computer doesn't generate random numbers. Instead, it has a long sequence of numbers that it generates, which looks more or less random - i.e. there is no discernable pattern. But every time I run my program, I just start over again with that same sequence.

To combat this, you can call srand(), which seeds the random number generator. Essentially, when you give srand a seed, it uses the seed to pick a starting point in this sequence of "random" numbers. With different starting points each time you run the program, you appear to be getting different sequences of random numbers.

Typically, you use the time() function from ctime to seed your random number generator. Since the time changes each time you run the program, you should get different sequences of "random" numbers. The following program shows how this all works:


#include <cstdlib>
#include <ctime>
#include <iostream>
using namespace std;

int main()
{
  // Seed the random number generator based on the time
  srand(time(0));

  // Print out 10 random numbers in the range [0,1]
  for(int i = 0; i < 10; i++)
    cout << double(rand())/RAND_MAX << " ";
  cout << endl;

  return 0;
}

exit(1)

Q: If you want to exit the program, and you're not in main(), you can't just do "return 0;". Why?

A: Because it would only return from the current function.

So there is a function "exit" that you can call to exit from anywhere. In particular, consider the following statement:


exit(0);    // requires #include <cstdlib>
It will exit the program, no matter where you are.

Note

Arrays: More Practice

Basic problems

Consider this data file: numbers.txt.

Write the following programs:

  1. min & max (solution: min & max)
  2. average (solution: average)
  3. standard deviation (solution: standard deviation)

Other Array Problems

  1. Start with the program:
    
    #include <iostream>
    using namespace std;
    
    int main()
    {
      // read size n, allocate array of n doubles, read values into array
      int n;
      cin >> n;
      double * A = new double[n];
      for(int i = 0; i < n; i++)
        cin >> A[i];
    
      // Now what?
    
      return 0;
    }
    
    ... and add code after the "Now what?" comment to solve one of the problems below for the array A of n elements created in the first part of the code.
    1. Print out the index of the minimum element in the array. So, for example:
      ~/$ ./ex1a
      4
      34 12 8 29
      minimum element is A[2] = 8.
      Solution: TE7a.cpp
    2. Print elements of the array, separated by commas. So, for example:
      ~/$ ./ex1b
      4
      34 12 8 29
      A = [34, 12, 8, 29]
      Solution: TE7b.cpp
    3. Create and print array of the "partial differences" of consecutive elements in the array. Here's an example of a sequence of four numbers along with the sequence of partial differences (note that there are only three elements in that sequence).
      3  7   8   5
      \_/ \_/ \_/
       4   1  -3
      A run of your program should look like this:
      ~/$ ./ex1c
      4
      14 16 8 29
      2 -8 21
      Solution: TE7c.cpp
    4. Split positive and negative. I actually want you to create two new arrays, one containing the positive elements of A, and one containing the negative elements of A. Zero's in A should be ignored. These arrays should be exactly the right size (no extra cells), and you program should print each array out. A run of your program should look like this:
      ~/$ ./ex1d
      10
      0 1 2 -3 4 -5 -6 7 8 9
      negative: -3 -5 -6
      positive: 1 2 4 7 8 9
      Solution: TE7d.cpp
  2. histograms (arrays of counters)
  3. masks (i.e. an array of bools), for example to implement a simple word-guessing game.