Here we explain some new features in the code nr.cc.
|
N is used
twice in the code. It is good practice to refer to it as a symbol and
define the value of the symbol only once. Then if we change its
value, we need to make only one change and don't have to search the code.
The #define statements should come near the top of the code
where they are easy to find. The symbol N is technically
called a ``macro''. The compiler preprocessor automatically replaces
every instance of the macro with its value before turning the code
over to the compiler. So N is not a variable, has no specific
type, and is not allocated storage.
|
for loop. It specifies that the statements
between the braces should be executed repeatedly as long as i < N, starting with i = 0 and increasing i by one when the last statement in the braces is reached.
We use a for loop here to impose a maximum number of Newton
Raphson iterations, and prevent the code from running on endlessly.
The generic pattern is
for(starting-statement; logical-expression; incrementing-statement){
statement block
}
Note that the logical expression is tested before entering the
block of statements. So in the above example, if it happened that
N == 0 the condition i < 0 would be false
and the statement block would be skipped altogether.
Because incrementing a counter by one unit is done so often, C++ has a
shorthand, i++ in place of i = i + 1; you
will often see a for loop written this way:
for(i = 0; i < N; i++){
...
}
It is also written ++i. In this context it means the same
thing.
We could accomplish the same thing with a while loop. Here is
the logically equivalent pattern;
i = 0;
while(i < N){
...
i++;
}
Notice that here we have to take care to place the initialization and
incrementing statements in the correct place. And it takes three
statements to do the job of one for statement. For those
reasons the for loop is preferable here.
The generic form is
while(logical-expression){
statement-block
}
The while loop repeats the statements inside the statement block as
long as the logical expression is true. It is up to the programmer to
assure that there is an escape from the loop, so it doesn't run on
indefinitely - another reason to be cautious about using a while
loop where a for loop will do.
The do ... while structure is much less used. The general
syntax is
do{
statement-block;
} while(logical-expression);
This loop structure is very similar to the while loop
structure, except that the logical expression is checked only after
executing the statement block at least once. (With the while
loop the statement block is not executed at all if the logical
expression is false.) Then in both cases the block is executed
repeatedly as long as the logical expression remains true.
|
|
tcsh using the Unix command
echo $statusimmediately after your program exits. In the
bash or
sh shell the command is echo $?.
Another common way to exit the main program is to call the exit
function as in
exit(0);
where the number in parentheses is the desired exit code.
The break statement provides another way out of a loop.
We could have written
for(i = 0; i < N; i = i + 1){
...
if(abs(p-pnew) < tol)break;
}
The break statement immediately quits the statement block controlled
by a for, while or do ... while
loop, and proceeds with the next statement after the closing brace.
The logical problem in this case is that we reach the same point in
the code if the process doesn't converge. So we need to check the
value of i to be sure that didn't happen. For example, we
could end it this way:
for(i = 0; i < N; i = i + 1){
...
if(abs(p-pnew) < tol)break;
}
if(i >= N){
cerr << "Failed to converge after " << N << " iterations.\n";
return 1;
}
cout << "Root is " << pnew << " to within "
<< tol << "\n";
return 0;
For completeness we mention the continue statement. It
provides another way to skip around in a loop. While break skips the rest of the statement block and quits the
loop, the continue statement skips the rest of the
statement block and proceeds with the next iteration. Here is an
example of its use in the same code:
for(i = 0; i < N; i = i + 1){
...
if(abs(p-pnew) > tol)continue;
cout << "Root is " << pnew << " to within "
<< tol << "\n";
return 0;
}
cerr << "Failed to converge after " << N << " iterations.\n";
return 1;
Notice that the inequality is reversed so the loop continues as long
as the shift in the root is larger than the tolerance and i < N.
I find the original coding style clearer, however, since the code
handling the special case is set off clearly with braces and indentation.
The continue statement is more appropriate when the standard
nesting of statement blocks is awkward or when continuation is the
unlikely alternative, which is not the case here.
|
iostream object cerr works just like cout but sends the output to the stderr device
instead of stdout. By default the stderr
device, like the stdout device, is the console. The main
reason for using it for error messages is that if a user is
redirecting standard output to a file or pipe, the error message would
still appear on the screen rather than disappearing into the file or
pipe and possibly being ignored.