7.8.1. average.cpp

Random Number Generators (Optional)
Time: 00:03:36 | Download: Large, Large (CC), Small | Streaming, Streaming (CC) | Slides (PDF)
Time: 00:07:20 | Download: Large, Large (CC), Small | Streaming, Streaming (CC)

The following programs demonstrate C++'s array syntax by filling an array with numbers and calculating their average. The array elements can operate as l- and r-values, appearing on the left and right sides of the assignment operator. Each version is slightly more complex than the previous one. The first two versions fill the array with a fixed number of pseudo-random values, while the third fills the array with an indeterminate number of values input from the console. The first program consists of a single function, while the second and third introduce an average function. The function's first implementation isn't very flexible. However, the final program demonstrates a general, flexible implementation that manages an array of any size, potentially less than its capacity.

Array Averaging Program 1

#include <iostream>
#include <random>								// (a)
#include <chrono>
using namespace std;

int main()
{
	default_random_engine
		rng((unsigned)(chrono::system_clock::now().time_since_epoch().count()));	// (b)
	uniform_int_distribution<int>	range(1, 100);				// (c)

	int	numbers[10];							// (d)

	for (int i = 0; i < 10; i++)						// (e)
		numbers[i] = range(rng);

	double	sum = 0;							// (f)

	for (int i = 0; i < 10; i++)						// (g)
		sum += numbers[i];

	cout << "The average is " << sum / 10 << endl;				// (h)

	return 0;
}
average 1: Single function version. This example creates a 10-element array and fills it with pseudo-random numbers. The first two statements, (b) and (c), create and use objects generating the pseudo-random1 numbers. These statements use a variety of syntactic elements not described until later in the text, but the current chapter has introduced the illustrated array operations.
  1. The header files for the pseudo-random number generation and time-of-day systems. The first provides the class specifications for default_random_engine and uniform_int_distribution; the second provides the class specification for chrono::system_clock.
  2. rng is an instance of default_random_engine, a C++ class implementing a pseudo-random number generator.
  3. range is an instance of uniform_int_distribution<int>, a class implementing a uniform distribution.
  4. Defines a one-dimensional, 10-element array.
  5. Fills the array with 10 pseudo-random numbers; each number is in the range [1-100].
  6. Defines and initializes an accumulator variable; the variable is defined as a double, preventing a truncation error in step (h)
  7. Calculates the total of all the numbers.
  8. Prints the average; sum is type double, so the division operation takes place using floating-point arithmetic.

Array Averaging Program 2

The second version of the program adds an average function to demonstrate passing a one-dimensional array as a function argument. The example illustrates two significant aspects of passing arrays as function arguments:

  1. By default, C++ passes most data types to functions by value. Arrays are the exception to this rule - C++ always passes arrays by-pointer. The example shows two versions of the function prototype and the function header. The different versions are equivalent, and programs only need one.
  2. Only the array's name appears in the function call because the name, without the square brackets, is a pointer - the array's address.
#include <iostream>
#include <random>
#include <chrono>
using namespace std;

//double average(int a[]);							// (a)
double average(int* a);

int main()
{
	default_random_engine
		rng((unsigned)(chrono::system_clock::now().time_since_epoch().count()));
	uniform_int_distribution<int>	range(1, 100);

	int	numbers[10];

	for (int i = 0; i < 10; i++)
		numbers[i] = range(rng);

	cout << "The average is " << average(numbers) << endl;			// (b)

	return 0;
}

//double average(int a[])							// (c)
double average(int* a)
{
	double	sum = 0;							// (d)

	for (int i = 0; i < 10; i++)						// (e)
		sum += a[i];

	return sum / 10;							// (f)
}
average 2: average function version. This program is an intermediate version transitioning between Figures 1 and 3. Although it adds an average function, it lacks a feature necessary for a useful, general-purpose average function.
  1. Function prototypes: choose one of the two ways to specify a one-dimensional array parameter.
  2. Call the average function and print the returned value. numbers is the array's address, passed to the function by-pointer.
  3. Function header: choose one of the two ways of specifying a one-dimensional array parameter.
  4. Define and initialize an accumulator variable.
  5. Total the numbers in the array. The function assumes the array's size is 10 - it only works with an array of 10 numbers!
  6. Calculate and return the average.

Array Averaging Program 3

There is a potential advantage to making the average operation a function: it could be used wherever a program needs that functionality. However, we must generalize the average function before we can realize the advantage.

  1. In Java, an array is an object that consists of data and length variables. So, when a Java program passes an array to a method, its length is part of it. In C++, an array is a simple, fundamental type with no attributes - it only contains the array elements. So, C++ programs must pass two arguments to the average function: the data and the array's length.
  2. Following that modification, the average function will accept a one-dimensional integer array of any length
  3. The function will also work with partially filled arrays. The data must start at location 0 and must be contiguous (i.e., no empty array elements in the data), but the data does not need to extend to the end of the array.
  4. We could further generalize the function by putting it in a separate .cpp file, making it even easier to use wherever the average functionality is needed. C++ does something similar to this with functions like sqrt and pow.
#include <iostream>
using namespace std;

double average(int size, int* a);						// (a)

int main()
{
	int	scores[1000];							// (b)
	int	count  = 0;							// (c)

	do
	{
		int	score;
		cout << "Please enter a score: ";
		cin >> score;
		if (score != -1)						// (d)
			scores[count++] = score;				// (e)
		else
			break;
	} while (count < 1000);							// (f)

	if (count == 1000)							// (g)
		cout << "The number of entered scores exceeds 1000" << endl;
	else if (count > 0)
		cout << "The average is " << average(count, scores) << endl;	// (h)
	else
		cout << "No scores entered\n";

	return 0;
}

double average(int size, int* a)						// (i)
{
	double sum = 0;

	for (int i = 0; i < size; i++)
		sum += a[i];

	return sum / size;
}
average 3: Console input and flexible average version. This version of the program allows users to enter any number of non-negative scores. Input ends when the user enters a -1 or the array is full. The program calculates and prints the average of all scores.
  1. Function prototype.
  2. At compile-time, programmers can't know how many scores the user will enter, so the program makes the array big enough to hold many scores - typically more than necessary.
  3. Defines and initializes the accumulator the program uses to count the scores as the user enters them.
  4. The user ends data input by entering a -1.
  5. Places the entered score into the scores array and counts it.
  6. The do-while loop ends the program when the array is full, preventing a buffer overrun error.
  7. Prints a diagnostic if the user attempts to enter too many scores.
  8. Calls the average function and prints the returned value. size is the number of array elements that contain data, not the array's capacity. Note that scores.length does not work in C++.
  9. The size parameter drives all average function operations that depend on the array's size, allowing the function to operate on all one-dimensional arrays.


  • Pseudo-random numbers are not random - they arise from deterministic calculations - but look random (i.e., pass some statistical tests of randomness). Pseudo-random number generators produce a long cycle of numbers (i.e., a sequence of numbers that eventually repeats) using a recurrence relation: Rn=f(Rn-1). Programs typically use a relatively small part of the cycle, increasing its random appearance. Programs start a random number generator at some point in the cycle by specifying a "seed" value: an initial Ri.

    Pseudo-random number generators frequently use the computer's clock to get the elapsed time since the epoch. The elapsed time is a monotonically increasing value - it remains unchanged between clock "ticks" but never decreases - making it an effective, low-cost seed value. Some generators can produce various distributions - a value's frequency of occurrence in a given range. The values in a uniform distribution are equally likely.

    Please see the optional Random Number Generators video at the top for more detail.