7.8.4. rms.cpp: Arrays, Functions, And Data Input

Time: 00:04:38 | Download: Large Small | Streaming
Review

The root mean square is a value used in statistics, physics, electronics, and numerous other fields. We approach it as just another problem involving formulas, arrays, functions, and data input. The formula is as follows:

\[ x_{rms} = \sqrt{{1 \over n} \sum_{i=0}^{n-1}x_i^2 } = \sqrt{{1 \over n} \left({x_0^2 + x_1^2 + ... + x_{n-1}^2} \right)} \] The picture maps parts of the summation notation to parts of a C++ for-loop. A sequence of variables, named x-sub-i, is at the formula's heart; we represent these variables with an array indexed with the loop-control variable: x[i]. The formula squares each variable, which C++ does with the pow function: pow(x[i], 3). The starting index value sometimes appears below the summation operator: i = 0. Similarly, the summation's end is sometimes shown above the operator: n - 1. These expressions become the first two expressions inside the for-loop's parentheses.
(a)(b)
Translating the root mean square to C++. The root mean square (RMS) example further demonstrates the conversion of the summation operator, Σ, to C++ code. Sometimes, the operator includes additional information about the problem. Although the information may make the formula look increasingly formidable, we can easily incorporate it into the C++ code. The conversion's "key" is recognizing that xi is a sequence of real numbers - an array of float or double C++ variables.
  1. Two equivalent versions of the RMS formula as it might appear in a textbook or problem statement. The second version highlights the solution's steps:
    1. Square each number.
    2. Add the squares together.
    3. Divide the sum by n (i.e., the number of numbers in the sequence).
    4. Calculate the square root of the quotient.
  2. The picture illustrates how parts of the summation notation map to the elements of a C++ for-loop.
    • xix[i]
    • xi2pow(x[i], 2)
    • Σ xi2sum += pow(x[i], 2)
    • i = 0 and n - 1 → for (i = 0; i < n; ...)

The RMS Function

The for-loop presented in the previous figure is the central part of the RMS function. Adding a function header, a variable definition and initialization, and a return statement completes the function.

//double rms(double x[], int n)		// (a)
double rms(double* x, int n)
{
	double sum = 0;			// (b)

	for (int i = 0; i < n; i++)
		sum += pow(x[i], 2);

	return sqrt(sum / n);		// (c)
}
C++ RMS Function. It's conceivable that a statistical, scientific, or engineering program may need to calculate many RMS values; it's equally conceivable that many programs may need to solve an RMS problem. Both cases imply the value of implementing the RMS calculation as a function.
  1. Two versions of the function's header, illustrating two ways of defining the array parameter, x. The function doesn't limit the array's size or length, but the client program must indicate how many numbers the array contains, n.
  2. C++ (ANSI 2011 standard) has several versions of the pow function. The return type of most versions follows the argument type. Since x is an array of double, the pow function's return type is also double. Therefore, we define sum as a double to avoid truncation errors. The function initializes sum and uses it as an accumulator.
  3. The final statement calculates - divides the sum by n (sum is a double, so no casting is needed) and takes the square root of the quotient - and returns the RMS value.

RMS Program

To complete the program, we add variable definitions, input and output operations, a call to the rms function, and some miscellaneous syntax. Unlike previous examples, this program can process all real numbers, including -1, implying that we must devise another data input technique. The program prompts the user to continue entering data or end input and complete the calculation. While this approach is somewhat cumbersome, it allows us to explore the get and ignore functions.

#include <iostream>
#include <cmath>
using namespace std;

//double rms(double x[], int n);						// (a)
double rms(double* x, int n);

int main()
{
	const	int	MAX = 100;						// (b)

	int	n = 0;								// (c)
	double	x[MAX];								// (d)
	//double* x = new double[MAX];						// (e)
	int	answer;

	cout << "Enter an x value [y/n]: ";
	while (n < MAX && ((answer = cin.get()) == 'y' || answer == 'Y'))	// (f)
	{
		cin >> x[n++];
		cout << "Enter an x value [y/n]: ";
		cin.ignore();							// (g)
	}
	//for (int i = 0; i < n; i++) cout << x[i] << endl;			// (h) temporary: validate input

	if (n > 0)								// (i)
		cout << "rms = " << rms(x, n) << endl;

	// delete x;								// (j)

	return 0;
}
The RMS program. The program must read an unknown number of data values while allowing the user to signal the end of the input. Since all numeric values are valid data, the program cannot use a specific value to signal the end of the input.
  1. The rms function prototype (either works).
  2. Symbolic constant for the maximum array size.
  3. The number of data items entered.
  4. Array allocated on the stack.
  5. Array allocated on the heap - data entry and rms function are unchanged.
  6. The inner parentheses, in gold, are the function call operator. In light blue, the grouping parentheses force the function call and assignment to run first. In red, the second pair of grouping parentheses force the evaluation of the logical-OR operation to occur before the logical-AND. The outer parentheses, in black, are part of the while-loop notation.
  7. Discards the newline character.
  8. Temporary code testing the input loop but removed from the final program.
  9. Only calls the rms function if the user entered data.
  10. Removes the array if it was allocated on the heap.