For each function that you write, it is often useful to write a test program that makes sure that you get expected results. This process is called unit testing.
For example, a square root function:
double
square_root(double d)
{
return pow(d, 0.5);
}
is expected to calculate the square root of d.
We can write a test program, where we precalculate, by hand, the square root of a single value, or better yet, a range of values. Then we can compare the returned value of our square root function to make sure that it works correctly:
#include <iostream.h> // needed for cout, <<, endl
#include <math.h> // needed for pow()
double square_root(double d);
int
main()
{
const double NUMBER = 4.0;
const double EXPECTED_ROOT = 2.0;
double root = square_root(NUMBER);
if (root != EXPECTED_ROOT)
{
cout << "Problem with square_root: expected "
<< EXPECTED_ROOT << ", got " << root << endl;
}
return 0;
}
double
square_root(double d)
{
return pow(d, 0.5);
}
With an array of values, you can use a loop to test square roots for each value:
#include <iostream.h>
#include <math.h>
double square_root(double);
struct value
{
double number;
double root;
};
const value TEST_VALUE[] =
{
{ 0.0, 0.000000000000000 },
{ 1.0, 1.000000000000000 },
... // actual data deleted (see the real program)
{ 98.0, 9.899494936611665 },
{ 99.0, 9.949874371066199 },
{ 100.0, 10.000000000000000 }
};
const int N_VALUES = sizeof(TEST_VALUE) / sizeof(TEST_VALUE[0]);
int
main()
{
for (int i = 0; i < N_VALUES; i++)
{
double root = square_root(TEST_VALUE[i].number);
if (root != TEST_VALUE[i].root)
{
cout.setf(ios::showpoint);
cout.precision(15);
cout << "Problem with square_root: expected "
<< TEST_VALUE[i].root << ", got " << root;
cout.precision(4);
cout << " (" << TEST_VALUE[i].number << ")"
<< endl;
}
}
return 0;
}
double
square_root(double d)
{
return pow(d, 0.5);
}
When this program is compiled under Windows NT Workstation 4.0 (Service Pack 3), using the Microsoft C/C++ compiler (version 11.00.7022 for 80x86) and executed on an Intel Pentium II system, the output is as follows:
Problem with square_root: expected 1.41421356237309, got 1.41421356237310 (2.000) Problem with square_root: expected 1.73205080756888, got 1.73205080756888 (3.000) Problem with square_root: expected 2.64575131106459, got 2.64575131106459 (7.000) Problem with square_root: expected 2.82842712474619, got 2.82842712474619 (8.000) Problem with square_root: expected 3.16227766016838, got 3.16227766016838 (10.00) Problem with square_root: expected 3.46410161513775, got 3.46410161513775 (12.00) Problem with square_root: expected 3.74165738677394, got 3.74165738677394 (14.00) Problem with square_root: expected 5.09901951359279, got 5.09901951359278 (26.00) Problem with square_root: expected 6.16441400296898, got 6.16441400296898 (38.00) Problem with square_root: expected 6.32455532033676, got 6.32455532033676 (40.00) Problem with square_root: expected 6.40312423743285, got 6.40312423743285 (41.00) Problem with square_root: expected 7.07106781186548, got 7.07106781186548 (50.00) Problem with square_root: expected 7.34846922834954, got 7.34846922834953 (54.00)
Note that certain test values result in very small square root errors (on the order of 10-14 or less). Whether or not these errors are acceptable depends on your application: for example, for measuring microscopic distances, such an error may be significant. If you are calculating current by taking the square root of power and dividing by resistance, then that sort of error is insignificant (i.e., hundredths of a picoamp!).
In Assignment #1, we had to write a function to sort the teams in order. It called a compare function to determine which items to switch. We can first write a program to test the compare function, and then another program to test the sort function.
To keep it simple, use a team structure with only number of points and number of wins in it.
The compare test program makes sure that the comparison function actually works the way we think it does: if Team A has more points than Team B, then A > B. If the points are the same, then the team with more wins is greater. If both points and wins are the same A == B. Otherwise, A < B.
#include <iostream.h>
struct team
{
int points;
int wins;
};
inline ostream &
operator<<(ostream & ostr, const team & theTeam)
{
ostr << "(P" << theTeam.points << ",W" << theTeam.wins
<< ")";
return ostr;
}
int
compare(const team & a, const team & b)
{
int d;
if ((d = a.points - b.points) != 0)
{
return d;
}
return (a.wins - b.wins);
}
int
main()
{
const team FIRST = { 30, 10 };
const team SECOND = { 20, 10 };
const team THIRD = { 20, 9 };
if (compare(FIRST, SECOND) <= 0)
{
cout << "Problem with compare: " << FIRST
<< " <= " << SECOND << endl;
}
if (compare(FIRST, THIRD) <= 0)
{
cout << "Problem with compare: " << FIRST
<< " <= " << THIRD << endl;
}
if (compare(SECOND, THIRD) <= 0)
{
cout << "Problem with compare: " << SECOND
<< " <= " << THIRD << endl;
}
if (compare(SECOND, FIRST) >= 0)
{
cout << "Problem with compare: " << SECOND
<< " >= " << FIRST << endl;
}
if (compare(THIRD, FIRST) >= 0)
{
cout << "Problem with compare: " << THIRD
<< " >= " << FIRST << endl;
}
if (compare(THIRD, SECOND) >= 0)
{
cout << "Problem with compare: " << THIRD
<< " >= " << SECOND << endl;
}
if (compare(FIRST, FIRST) != 0)
{
cout << "Problem with compare: " << FIRST
<< " != " << FIRST << endl;
}
if (compare(SECOND, SECOND) != 0)
{
cout << "Problem with compare: " << SECOND
<< " != " << SECOND << endl;
}
if (compare(THIRD, THIRD) != 0)
{
cout << "Problem with compare: " << THIRD
<< " != " << THIRD << endl;
}
return 0;
}
The compare function must be working before we can test the sort function because sort depends on compare. We can also use compare to check if our array is sorted correctly, i.e., that each team is greater than the next team.
#include <iostream.h>
struct team
{
int points;
int wins;
};
inline ostream &
operator<<(ostream & ostr, const team & theTeam)
{
ostr << "(P" << theTeam.points << ",W" << theTeam.wins <<
")";
return ostr;
}
int compareTeams(const team &, const team &);
void sortTeams(team [], int);
int
main()
{
team nhl[] =
{
{ 30, 10 },
{ 10, 4 },
{ 20, 10 },
{ 20, 9 },
{ 40, 11 }
};
int n_teams = sizeof(nhl) / sizeof(nhl[0]);
int i;
sortTeams(nhl, n_teams);
for (i = 0; i < n_teams - 1; i++)
{
if (compareTeams(nhl[i], nhl[i + 1]) < 0)
{
cout << "Problem with sort: team " << i
<< nhl[i] << " < team " << (i + 1)
<< nhl[i + 1] << endl;
}
}
return 0;
}
int
compareTeams(const team & a, const team & b)
{
int d;
if ((d = a.points - b.points) != 0)
{
return d;
}
return (a.wins - b.wins);
}
inline void
switchTeams(team & a, team & b)
{
team temp = a;
b = a;
a = temp;
}
void
sortTeams(team teamArr[], int n)
{
int i, j;
for (i = 0; i < n - 1; i++)
{
for (j = i; j < n; j++)
{
if (compareTeams(teamArr[i], teamArr[j]) < 0)
{
switchTeams(teamArr[i], teamArr[j]);
}
}
}
}
Finally, when both functions are working, we can hook them up to our main program and run it with real data. This is called integration testing.
Download the square root test program (scalar version)