One of the first homework assignments in this course is to write a program which computes the motion of a ball tossed upwards gently from the Earth's surface. The situation is very simple -- no air resistance, a constant force due to gravity -- and so it might seem that one can satisfy the assignment with a short, simple program. For example,
Does the program work? Let's try giving it some reasonable input:
>> ball_euler1(20, 1) t 0.000 y 0.000 vy 20.000 E 2.000000e+02 f 0.0000e+00 t 1.000 y 20.000 vy 10.200 E 2.480200e+02 f 2.4010e-01 t 2.000 y 30.200 vy 0.400 E 2.960400e+02 f 4.8020e-01 t 3.000 y 30.600 vy -9.400 E 3.440600e+02 f 7.2030e-01 t 4.000 y 21.200 vy -19.200 E 3.920800e+02 f 9.6040e-01 t 5.000 y 2.000 vy -29.000 E 4.401000e+02 f 1.2005e+00 t 6.000 y -27.000 vy -38.800 E 4.401000e+02 f 1.2005e+00 >>
Yes, that's correct.
But -- what if we give the program some unreasonable input values?
>> ball_euler1(20, 0) t 0.000 y 0.000 vy 20.000 E 2.000000e+02 f 0.0000e+00 t 0.000 y 0.000 vy 20.000 E 2.000000e+02 f 0.0000e+00 t 0.000 y 0.000 vy 20.000 E 2.000000e+02 f 0.0000e+00 t 0.000 y 0.000 vy 20.000 E 2.000000e+02 f 0.0000e+00 t 0.000 y 0.000 vy 20.000 E 2.000000e+02 f 0.0000e+00 t 0.000 y 0.000 vy 20.000 E 2.000000e+02 f 0.0000e+00 t 0.000 y 0.000 vy 20.000 E 2.000000e+02 f 0.0000e+00 t 0.000 y 0.000 vy 20.000 E 2.000000e+02 f 0.0000e+00 t 0.000 y 0.000 vy 20.000 E 2.000000e+02 f 0.0000e+00 t 0.000 y 0.000 vy 20.000 E 2.000000e+02 f 0.0000e+00 t 0.000 y 0.000 vy 20.000 E 2.000000e+02 f 0.0000e+00 t 0.000 y 0.000 vy 20.000 E 2.000000e+02 f 0.0000e+00 t 0.000 y 0.000 vy 20.000 E 2.000000e+02 f 0.0000e+00 t 0.000 y 0.000 vy 20.000 E 2.000000e+02 f 0.0000e+00 t 0.000 y 0.000 vy 20.000 E 2.000000e+02 f 0.0000e+00 t 0.000 y 0.000 vy 20.000 E 2.000000e+02 f 0.0000e+00 t 0.000 y 0.000 vy 20.000 E 2.000000e+02 f 0.0000e+00 (continues forever)
Whoops. The program became stuck in an infinite loop. That's no good.
Or what if the user makes an even worse mistake?
>> ball_euler1(20, 'ten seconds') t 0.000 y 0.000 vy 20.000 E 2.000000e+02 f 0.0000e+00 Error using * Inner matrix dimensions must agree. Error in ball_euler1 (line 55) ke = 0.5*m*vy*vy; >>
Huh? The program crashes somewhere in the midst of its calculations. That's no good, either, especially since it did print out one line of valid output, which might confuse some person or program analyzing the results later.
The problem here is that we haven't been checking the input arguments for validity before using them. That's bad programming practice. A well-made scientific program will always, always examine the values of its input arguments carefully before it starts to calculate anything. If it finds any error or ambiguity, it should print an error message and return control to its calling procedure immediately.
Let's continue using the trajectory-of-a-ball program to illustrate this point. The relevant section of the code lies here, between the end of the initial comment block and the start of the real calculations:
% Usage: ball (initial_velocity, timestep) % % where % initial_velocity is initial speed of ball % vertically upward (m/s) % % timestep is size of steps in time (s) % % Returns: nothing % % MWR 11/28/2012 Should check input arguments here % initialize variables % current height above the ground (m) y = 0; |
We need to add a block of argument-checking code before any of the real calculations begin. In general, this block will contain a set of if-then statements; in case any of the checks fail, the code will print an error message and then use the return statement to stop execution.
Below is a version of the program with some minimal checking of the input arguments. Note that this version also includes statements in the "help comments" which tell the user about the conditions attached to the input arguments. In this manner, any user who types help ball_euler1 will see that it is illegal to give a negative initial velocity for the ball.
% Usage: ball (initial_velocity, timestep) % % where % initial_velocity is initial speed of ball % vertically upward (m/s) % Must be >= 0 m/s % % timestep is size of steps in time (s) % Must be >= 0 s % % Returns: nothing % % MWR 11/28/2012 % check input arguments if (initial_velocity <= 0) fprintf(1, 'error: initial velocity must be greater than zero \n'); return; end if (timestep <= 0) fprintf(1, 'error: timestep must be greater than zero \n'); return; end % initialize variables % current height above the ground (m) y = 0; |
But is this improved version really solid? No. It still fails if the user provides a string as one of the arguments.
>> ball_euler1(20, 'foo'); t 0.000 y 0.000 vy 20.000 E 2.000000e+02 f 0.0000e+00 Error using * Inner matrix dimensions must agree. Error in ball_euler1_checkarg (line 65) ke = 0.5*m*vy*vy; >>
A really paranoid programmer will check to make sure that each argument is a numeric value, and THEN verify that all supplied values fall into an acceptable range.
% Usage: ball (initial_velocity, timestep) % % where % initial_velocity is initial speed of ball % vertically upward (m/s) % Must be >= 0 m/s % % timestep is size of steps in time (s) % Must be >= 0 s % % Returns: nothing % % MWR 11/28/2012 % check input arguments if (isnumeric(initial_velocity) ~= 0) fprintf(1, 'error: initial velocity argument must be a number \n'); return; end if (initial_velocity <= 0) fprintf(1, 'error: initial velocity must be greater than zero \n'); return; end if (isnumeric(timestep) ~= 0) fprintf(1, 'error: timestep argument must be a number \n'); return; end if (timestep <= 0) fprintf(1, 'error: timestep must be greater than zero \n'); return; end % initialize variables % current height above the ground (m) y = 0; |
There. Now even a truly clueless user will be given the feedback he needs to get things right:
>> balll_euler1(20, 'foo'); error: initial velocity argument must be a number >>
Copyright © Michael Richmond. This work is licensed under a Creative Commons License.