Print information during execution
The best way to find errors is to print a lot of information about the internal
state of the program. For instance, if a program remains frozen, the first thing
to do is to print something when a few checkpoints are met
cout << "Checkpoint #1\n";
for(int i = 1; i < 1000; i++) cout << "i = " << i << "\n";
cout << "Checkpoint #2\n";
for(int j = 0; j < 100; j = j*2) cout << "j = " << j << "\n";
cout << "Checkpoint #3\n";
Also, printing values supposed to vary or to remain constant is a good way to
spot errors.
Write the same routine twice
Usually, any routine can be written in a short, dirty, computationally expensive
and maybe even numerically approximative way. This is a good technique to
check that the fancy and correct version does what it is supposed to do. For
instance, computation of a derivative
double f(double x) {
return sin(sin(x) + cos(x));
}
double derivative_of_f(double x) {
// should be (cos(x) - sin(x)) * cos(sin(x) + cos(x));
return (cos(x) + sin(x)) * cos(sin(x) + cos(x));
}
double derivative_of_f2(double x) {
return (cos(x) - sin(x)) * cos(sin(x) + cos(x));
}
double dirty_derivative_of_f(double x) {
double epsilon = 1e-5;
return (f(x + epsilon) - f(x - epsilon))/(2 * epsilon);
}
int main(int argc, char **argv) {
double x= 0.2345;
cout << "The 1st fancy one: " << derivative_of_f(x) << "\n";
cout << "The 2nd fancy one: " << derivative_of_f2(x) << "\n";
cout << "The dirty one: " << dirty_derivative_of_f(x) << "\n";
}
produces
The 1st fancy one: 0.43103
The 2nd fancy one: 0.2648
The dirty one: 0.2648
A last way consists of checking a global property of the result. For instance
sort_my_array(a, size);
#ifdef DEBUG
for(int i = 0; i < size-1; i++) if(a[i] > a[i+1]) {
cerr << "hoho ...\n";
abort();
}
#endif
Heavy invariants
A last way consists of checking a global property of the result. For instance
sort_my_array(a, size);
#ifdef DEBUG
for(int i = 0; i < size-1; i++) if(a[i] > a[i+1]) {
cerr << "hoho ...\n";
abort();
}
#endif