Programming Tools Tutorial Notes Edmund A. Hajim  School of Engineering and Applied Sciences

Programming Tools


The intent of this tutorial is to present some of the programs and utilities available to the programmer that make software development easier. We do not aim to teach programming in any language.

It is assumed that you are relatively familiar with UNIX and with some programming language. Most of our examples use the C language. Most of the programs covered here support other languages, but some support only C.

Our hope is that after this tutorial, your productivity and enjoyment of the task of programming will improve.


Throughout this document the following conventions will be used:

Text appearing in the Helvetica Normal and Bold fonts, such as this, is instruction and narrative. Text appearing in the Courier font such as

	"error.c", line 1: variable undefined

represents text which the computer system prints.

Text appearing in the Courier Italic font such as

	lint -abchx mult.c

represents text which you type at the computer keyboard.

The symbols [RETURN] and [CR] both mean that you are to press the carriage return key on your keyboard. The symbol [ESCAPE] means that you are to press the escape key on your keyboard.

Compiling C Programs

The command "cc" will take as input files containing C source code, and produce either an executable program or object files ready to be linked into an executable program. (It can also generate assembly language files.)

In reality cc is more than just one program, it's a collection of programs that are invoked as needed by the main cc program. Typically, when you compile a C program, four programs are invoked by cc to generate an executable program.


Cpp is the C language preprocessor. Cpp is the program which recognizes the "#" preprocessor commands in your C programs. When cpp is done with your program, all the preprocessor commands have been "executed", and no longer appear in your program.

By default, cpp generates output which is optimized for use by a compiler. To see what cpp generates for the cc compiler, try "cpp " where is the file that contains your C source code. "cpp -P " will produce a more human friendly output.


Ccom is the actual C compiler. It takes as input source code which has been stripped of preprocessor commands, and generates an assembly language translation of the C code.


As is the assembler, it takes as input assembly language source code, and generates binary object files as output.


Finally, ld is the linking loader (sometimes known as the linking editor). Ld's job is to take binary object code and resolve any unresolved references. For example, if your program calls a subroutine such as printf which isn't defined in your program, ld will look through the system libraries (or other libraries that you specify) to find the object code for printf. ld then appends the object code to your program and adjusts all the references to printf. When done ld produces a complete, ready to run program.

Invoking cc

cc has a wide variety of options for itself and the programs it calls. Here is a brief description of some of the more popular ones. For more complete information see the man pages for cc, cpp, and ld.

-a	     Produce code with support for tcov.
-Bbinding    Select either "dynamic" (shared) or "static" (non-shared) libs.
-c	     Suppress linking with ld(1) and just produce a .o file.
-dryrun	     Display (without running) the cpp, ccom as and ld commands.
-Dname[=def] Define a cpp symbol.
-E	     Just run the source through cpp and send output to stdout.
-fast	     Set options to produce code optimized for the current machine.
-ffloat_opt  Select special floating point processing.
-g	     Produce debugger info for dbx.
-go	     Produce debugger info for adb.
-help	     Display helpful information about cc.
-Idir	     Add "dir" to the list of places cpp searches for include files.
-llib	     Link code with the library "lib".
-Ldir	     Add "dir" to the list of places ld searches for libraries.
-o pname     Final program will be called "pname".
-O	     Optimize the generated code.
-p	     Produce code with support for prof.
-pg	     Produce code with support for gprof.
-P	     Like -E but more readable and sent to a .i file.
-pipe	     Use pipes, rather than temp files, between compiler stages.
-Q	     Pass arguments to individual compiler stages.
-S	     Generate assembly code.
-temp	     Specify an alternate directory for temp files.
-Uname	     Undefine a cpp symbol.

Other C-like Languages

The "cc" command compiles what is known as "K&R" or "traditional" C. There are several other C-like languages available.


The ANSI version of C provides new features like prototypes and also more precisely specifies the behavior of certain C constructs. We have two ANSI C compilers available, Sun's "acc" and GNU's "gcc".


C++ is the latest in Object Oriented Programming Languages. In effect, it's regular C, with support of Object Programming available as a superset. In fact C++ is often implemented as a filter which translates your C++ program into normal C. The main reference for C++ is "The C++ Programming Language" By Bjarne Stroustrup.

For information on Sun's C++ compiler use "man CC". For info on the GNU C++ compiler use "man g++".

Objective C

Objective C is another object oriented version of C that is not in widespread use within HSEAS. The GNU compiler also supports Objective C, use "man g++" for more details.

Other Languages

Although it's sometimes hard to believe, there are other programming languages besides C. A couple which are worth mentioning are FORTRAN and Pascal.


The command "f77" will invoke Sun's FORTRAN-77 compatible compiler. In general, operation of this compiler is similar to that of cc. This compiler is a higher quality compiler than the FORTRAN compiler which is standard with UNIX systems. For more information use "man f77".


A Pascal compiler is available on the Sun workstations, via the command "pc". The usage is similar to cc and f77. For more information use "man pc".

Mixing Languages

Both the FORTRAN and the C compilers know how to invoke each other when they encounter programs written in the other language. This allows you to, for example, include a file containing FORTRAN source code in the list of files being passed to C. CC identifies the type of source code from the extension on the filename, i.e. all files that end in ".f" are assumed to be FORTRAN and all files that end in ".c" are assumed to be C. F77 can make a similar determination.

% cc interface.c math_routines.f

All FORTRAN common block and subroutines names have a "_" appended to them by the FORTRAN compiler. Thus, a C program is going to call a FORTRAN subroutine, the C program must specify the name of the subroutine with a trailing "_".

Conversely, if a FORTRAN program wishes to call a C function, the C function must be written with a trailing "_" in it's name. This means that you may have to write "glue" routines if your FORTRAN program is going to call pre-existing C functions.

Parameters to subroutines in FORTRAN are always passed by reference. This affects how your C routines call FORTRAN subroutines, and how C functions called by FORTRAN code must interpret their arguments.

Finally, parameters of type character being passed to FORTRAN subroutines, require a long int at the end of the parameter list, to specify the length of the string.


character*7 s string char string[7];
integer array(3) long int array[3];
.... ....
call doit (array(2), s) doit_(&array[1], string, 7L);

Note that FORTRAN numbers arrays starting at 1 while C starts at 0.

Useful Libraries

The library which provides support for mathematical computing, is known as the "math library". This library is conformant with the ANSI/IEEE standard for floating point math.

To use the library, you need to include a file which defines all the function calls:


When you compile your program, you need to specify the math library to the linker via "-lm" in the command which invokes the compiler.

You can read about the math library via the command "man 3m intro". In addition, each of the routines in the math library (listed in the appendix) has a man page to describe it.

The IMSL math libraries are also available. Some of the capabilities in the IMSL "MATH" library include:

	Linear Systems
	Eigensystem analysis
	Interpolation and approximation
	Integration and differentiation
	Differential equations
	Nonlinear equations
	Basic matrix/vector operations

Some of the capabilities in the "STAT" library are:

	Analysis of Variance
	Categorical and discrete data analysis
	Nonparametric statistics
	Tests of goodness-of-fit and randomness
	Time series analysis and forecasting
	Covariance structures and factor analysis
	Discriminant analysis
	Cluster analysis
	Survival analysis, life testing and reliability
	Multidimensional scaling
	Density and hazard estimation
	Line printer graphics
	Probability distribution functions and inverses
	Random number generation

You can link against the IMSL library via the option "-limsl" when you invoke the C compiler. Complete documentation is available from the system staff (or in Taylor Hall). There is no man page for IMSL.


Both of the standard UNIX shells have the capability to "execute scripts", which is another way of saying that you can create a file with commands for the shell to execute as a program.

The contents of the first line in the script will determine which shell executes the script.

- If the first line does not start with a "#", the Bourne shell is used.
- If the first line starts with a "#", and is NOT followed by a "!" then the C-shell is used.
- If the first line starts with a "#!" followed by the name of a program, that program is invoked to interpret the script.

The language associated with each shell is different. Here we'll talk about the Bourne shell, which is the more commonly available shell.

You can assign values to variable with the "=" sign.

$ count=1

You can substitute the value of a variable, by preceding it with a "$".

$ echo count is set to $count
count is set to 1

There are some special variables defined for you in the Bourne shell. For example: $1, $2, ... refer to the parameters that the script was invoked with. $# will return the number of parameters passed to your script.

Some of the flow control statements available in the Bourne shell include:


The if command will branch, based on the status returned from the command it executes.

	<command list 2>
	<command list 3>


For iterates through a list of words. Each time through the loop the variable is set to the next word. If no wordlist is given then iterates through the parameters $1, $2, ...

for <name> in <word1> <word2> ...
	<command list>


The while keyword allows you to loop, based on the return status of a command.

while <command 1>
	<command list 2>

Command 1 is executed, if it returns a status of 0 (success) then command list 2 is executed, and then control goes back to the top of the loop. If (when) command 1 fails and returns a non-zero status then the loop terminates.


Until is the opposite of while, it will loop until the command succeeds.

until <command 1>
	<command list 2>


The case keyword allows for a multi-way branch.

case <word> in
	<pattern1>)	<command list 1>;;
	<pattern2>)	<command list 2>;;
	*)	<default command list>;;



The command "test" allows you to determine the status of files and compare variables. Depending on how it's used, test will take a number of arguments.

test -f <file> returns 0 if the file <file> exists test -r <file> returns 0 if <file> exists and is readable test -w <file> returns 0 if <file> exists and is writeable test -z <string> returns 0 if the length of <string> is 0 test <string> = <string2> returns 0 if the strings are equal test <n1> -eq <n2> returns 0 if <n1> == <n2>. Also -ne -gt -lt or -le may be used.

The command test is frequently abbreviated as "[". E.g.:

if test $# -lt 1
is the same as:

if [ $# -lt 1 ]

Here is a sample program that demonstrates some of the shell features we have discussed.

$ cat show
#! /bin/sh
if test $# -lt 1
	echo Usage: show name ...
	exit 1
	for name
		ps -ax | grep $name
$ ./show grep csh
  319 p3 S     0:00 sh ./show grep csh
  320 p3 S     0:00 grep grep
  169 p1 SW    0:03 - (csh)
  170 p2 SW    0:02 - (csh)
  226 p3 SW    0:03 - (csh)
  319 p3 S     0:00 sh ./show grep csh
  322 p3 S     0:00 grep csh

A good description of Bourne shell programming is in appendix F of the manual "Doing More with UNIX: Beginners Guide", which should be available in the labs or via the "answerbook" command. The man page for "sh" will also give you a good description of the syntax of Bourne shell scripts.


Aside from the compilers, libraries, and script languages, there are a variety of tools at your disposal to make programming easier. These can be grouped into three types: debugging, programming, and profiling.

For the following discussion, we will often refer to our sample program, mult.c. This program simply multiplies two positive integers using a recursive adding algorithm.

unsigned int mult(a, b) unsigned int a, b; { if (a == 0) return 0; return b + mult(a - 1, b); } main(argc, argv) int argc; char *argv[]; { if (argc != 3) { puts("Usage: mult <num> <num>"); exit(1); } printf("%d\n", mult(atoi(argv[1]), atoi(argv[2]))); }


We're only human, and our programs are never perfect on the first try. Sometimes, bugs can be particularly difficult to track down, so there are a variety of programs available to help. Bugs come in several varieties... There are portability problems, logic errors, memory losses, and syntax errors.


The programs lint and alint check C programs for portability problems, syntax errors, wasteful style, and other forms of bugs; lint understands traditional C while alint is for ANSI C. Lint is extremely thorough and perfectly capable of making even the best programmer look bad. It is very strict about type checking, unreachable statements, loops not entered at the top, unused variables, logical expressions with constant values, inconsistent use of parameters and return values, and other such potential bugs.

Lint is used as follows:

	lint [options] filename ...

Lint takes several options, five of which are particularly useful.

  -a	Report assignments of long values to variables that are not long.
  -b	Report break statements that cannot be reached.
  -c	Complain about casts which have questionable portability.
  -h	Use heuristic tests to intuit bugs, improve style, and reduce waste.
  -x	Report variables referred to by extern declarations, but never used.

Using these five options, lint will most likely produce a ream of messages suggesting improvements to your program. It also takes standard C Pre-Processor options including -I, -D, -U, and also -l to mimic the use of libraries by the C compiler.

For instance, if we run lint -abchx mult.c, we get:

mult.c(21): warning: main() returns random value to invocation environment 
mult, arg. 1 used inconsistently	mult.c(4)  ::  mult.c(20)
mult, arg. 2 used inconsistently 	mult.c(4)  ::  mult.c(20)
exit value declared inconsistently	llib-lc(236)  ::  mult.c(17)
printf returns value which is always ignored


Lint is basically just a better syntax checker. Other types of debuggers allow you to run your program and examine its memory while it is running, or examine a core dump to determine where a program failed.

One such debugger is called "adb", which stands for "a debugger". An uncreative name for an uncreative debugger... Note that it is named similarly to the language "apl", or "a programming language". Both are equally cryptic and difficult to use. Nonetheless, adb remains a popular debugger for the hard-core programmer, and is available on nearly every version of UNIX in the world. It also has the advantage of not caring what language a program was written in.

More recent debuggers allow not only investigation and manipulation of a program's core memory, but investigation and tracing through the source code as well. Such debuggers are called "source debuggers" or "symbolic debuggers". The first such debugger for popular UNIX was called "sdb", but sdb has given way to "dbx". Dbx is now the standard debugger for UNIX today. Dbx supports C, Pascal, and FORTRAN-77.

To use dbx, a program must be compiled with the -g option. On many compilers, that means that you cannot use the -O option for optimization. The -g option means to include a symbol table in the compiled program. Note also that programs that have been "stripped", either with the -s option at link-time or the "strip" program, have no namelist or symbol table, and therefore cannot be debugged.

To use dbx to determine where a program died after a core dump, run

	dbx program

where program is the name of the program to debug. At the (dbx) prompt, say where. This will list the active functions on the stack; the one listed at the top (along with the exact line in the source code) is where the program died. Further investigation of the value of particular variables and such can also be done at that time.

Dbx also provides for a variety of traces and breakpoints, line-by-line and call-by-call step-throughs, investigation and manipulation of variables, memory, registers, signals and signal handlers, the stack, and more. Further documentation on dbx can be found in the on-line manual pages, hard copy documentation, and books written on the subject.


There is also a window system interface to dbx. This starts up with one window showing the current source file, another a text window into dbx, and an array of buttons. Each button functions just as though you typed the equivalent command to the text mode of dbx. The source window is kept up-to-date, showing the current line, breakpoints, and the like.


The GNU debugger is similar to dbx but provides many more features. It works best on programs that were compiled with gcc -g.


There are several tools of interest to use during software development, to increase productivity and ease your workload. In addition to the generally available ones covered where there are also commercial products available which perform similar functions, though generally in more depth. Such tools fall into the realm of CASE, or Computer Aided Software Engineering.


When writing a small, simple program, you compile with

	cc filename.c -o filename.  

However, when writing a large program with many modules, you don't want to recompile every module every time you make a change. It would be helpful to have a program to figure out exactly what has changed and compile only what needs to be compiled, and then relink if necessary.

Make is such a program. This is a simple language describing targets, dependencies, and rules. A target is a program to be built. Dependencies are things which must first be built in order to build the target. In order to build the target, certain rules are executed.

Make is also familiar with other languages, including FORTRAN, Pascal, and C++. It also has macro capabilities, other built-in rules, and other powerful capabilities.

Make is invoked simply by typing make. This will look for a file called "makefile" or "Makefile" in the current directory, and will process the rules there. The first target in the file is the one that will be built, unless another is specified on the command line. If you pass the -n argument to make, it will tell you what is out of date without actually doing anything.

For instance, a Makefile for our example program might look like this:


	BINDIR = /usr/ceas/bin
	MANDIR = /usr/ceas/common/man

	mult: mult.o
		cc -o mult mult.o

	install: mult
		install -s mult $(BINDIR)
		install -c mult.1 $(MANDIR)

		rm mult mult.o core

This makefile has three targets, with "mult" being the default. Mult cannot be built before mult.o is complete. Make automatically knows how to create .o files from .c files, so it will notice mult.c and compile it appropriately. Once mult.o is up-to-date, mult is linked using the rules underneath the target/dependency line.

If mult.c is changed, make will recompile it. Then, since mult.o has changed, make will automatically relink the object to create a new version of mult. The targets "install" and "clean" can be used to install the program and to remove the unnecessary files.

Make is an incredible time-saver when working on a large, multi-module program. It is also incredibly portable, with versions available for just about every computer known to man. It is also general enough to be used for much more than just programming... It's a good tool to become familiar with, as you will find uses for it all the time. More details can be found in the on-line and hard copy manuals, as well as several books written on the subject.


Most Emacs-style editors, such as JOVE and GNU Emacs (mentioned in our Editors and Formatters tutorial), have modes designed to aid programmers. When editing a C program (or similar language), the editors will do automatic tabification, parentheses matching, and other language-specific structure handling.

They can also automatically invoke make or the compiler, and parse the errors. For instance, if you had a syntax error in output.c on line 54, the editor would automatically open a buffer and window for output.c and put the cursor on line 54, so you could correct your error. Similarly, the editors can parse the output from lint or dbx. This is a good alternative to debugger, as you can run dbx in one buffer/window while actually editing and fixing source code bugs in the other.


Programming style is a personal topic. It can be very frustrating to work on a program written by someone else in a vastly different style. Therefore, there are programs to help translate source code from one style to another.

There are two such programs available on UNIX, both for the C language. The original is called "cb", for "C Beautifier". The style generated approximately matches that of Kernighan and Ritchie in the bible of C, "The C Programming Language".

Because cb is not particularly robust, most people prefer to use "indent". Indent goes overboard in the other direction, it is almost completely configurable for your particular style. As the man page reads, "indent has even more switches than ls." Indent is invoked as

	indent input-file [output-file] [options] [-troff]
The -troff option generates output suitable for processing with troff and printing on a typesetter or laser printer. This generates output much like "vgrind", which we discussed in the Editors and Formatters tutorial.

Also, as mentioned above, the Emacs-style editors can help you to program with a logical and consistent style. They do this automatically when invoked on a filename ending in ".c" or one of the other languages they are aware of.


The "profile" of a program is a breakdown of the program's execution, showing the amount of calls or the amount of time spent on any particular activity. Breakdowns can be by routine, by line, by block of code, or any other logical subset. Information presented might include the amount of CPU or real time spent, the number of times a line or routine is called, and a tree showing the hierarchy of procedure calls.

The purpose is to see where your program is spending most of its time, so that you can concentrate on optimizing that particular section of code for speed.


The oldest UNIX profiler is called "prof". To get the profile of a program using prof, it must be compiled with the -p option, and run once. Then, invoke prof as

	prof program

This will generate a list of functions and a variety of information about each one, sorted by the percentage of time that each one was running. It also shows the amount of time spent there, the number of calls to that routine, and the average time per call.

For instance, if we run prof on our sample program after running mult 1234 5678, we get the following results:

 %time  cumsecs  #call  ms/call  name
 100.0     0.04   1235     0.03  _mult
   0.0     0.04      7     0.00  .udiv
   0.0     0.04      7     0.00  .urem
   0.0     0.04      1     0.00  __doprnt
   0.0     0.04      1     0.00  __findbuf
   0.0     0.04      1     0.00  __wrtchk
   0.0     0.04      1     0.00  __xflsbuf
   0.0     0.04      2     0.00  _atoi
   0.0     0.04      1     0.00  _exit
   0.0     0.04      1     0.00  _main
   0.0     0.04      2     0.00  _malloc
   0.0     0.04      1     0.00  _memchr
   0.0     0.04      1     0.00  _on_exit
   0.0     0.04      1     0.00  _printf
   0.0     0.04      1     0.00  _profil
   0.0     0.04      1     0.00  _write


More recent versions of UNIX have a much better version of prof, called "gprof". Programs to be profiled with gprof must be compiled with the -pg option, and run once. Then, invoke gprof as

	gprof program

This will produce a long and detailed report about your program, including call-graph hierarchies as well as a flat profile like that produced by prof. The information presented is very thorough, though it is still broken down by routine as with prof. The output from a profile of our sample program is far too long to include here, but feel free to try it.


The Test COVerage analysis tool is used while testing a program for proper functioning. To use tcov you must first compile your program with the "-a" option. You can then run your program one or more times. During each run data is collected that tracks which lines of your program are being executed. You can then run

	tcov program.c 

which generates the coverage report in "program.tcov". Lines of code that have never been executed are a potential source of unknown bugs. Lines that get executed frequently are good candidates for optimization.


The software on the system was all written by programmers who have run into the same kinds of problems as the rest of us. Therefore, they have designed tools to help with these problems. No matter what task you are trying to accomplish, most likely it has already happened to someone else, and there is an easy way to solve it.

We hope that now, your frustration levels will go down and your productivity will increase.


The following functions are available in the math library (produced with "man 3m intro").

Name Man Page Description
- bessel(3M) Bessel functions
- frexp(3M) floating-point analysis
- hyperbolic(3M) hyperbolic functions
- ieee_functions(3M) IEEE classification
- ieee_test(3M) IEEE tests for compliance
- ieee_values(3M) returns double-precision IEEE infinity
- trig(3M) trigonometric functions
acos() trig(3M) inverse trigonometric functions
acosh() hyperbolic(3M) inverse hyperbolic function
aint() rint(3M) convert to integral value in floating-point format
anint() rint(3M) convert to integral value in floating-point format
asin() trig(3M) inverse trigonometric function
asinh() hyperbolic(3M) inverse hyperbolic function
atan() trig(3M) inverse trigonometric function
atan2() trig(3M) rectangular to polar conversion
atanh() hyperbolic(3M) inverse hyperbolic function
cbrt() sqrt(3M) cube root
ceil() rint(3M) ceiling function
convert_external() convert_external(3M) convert between binary formats
copysign() eee_functions(3M) copy sign bit
cos() trig(3M) trigonometric function
cosh() hyperbolic(3M) hyperbolic function
erf() erf(3M) error function
erfc() erf(3M) complementary error function
exp() exp(3M) exponential function
expm1() exp(3M) exp(X)-1
exp2() exp(3M) 2**X
exp10() exp(3M) 10**X
fabs() ieee_functions(3M) absolute value function
finite() ieee_functions(3M) test for finite number
floor() rint(3M) floor function
fmod() ieee_functions(3M) floating-point remainder
fp_class() ieee_functions(3M) classify operand
frexp() frexp(3M) floating-point analysis
hypot() hypot(3M) Euclidean distance
ieee_flags() ieee_flags(3M) IEEE modes and status
ieee_handler() ieee_handler(3M) IEEE trapping
ilogb() ieee_functions(3M) exponent extraction
infinity() ieee_values(3M) returns double-precision IEEE infinity
irint() rint(3M) convert to integral value in integer format
isinf() ieee_functions(3M) IEEE classification
isnan() ieee_functions(3M) IEEE classification
isnormal() ieee_functions(3M) IEEE classification
issubnormal() ieee_functions(3M) IEEE classification
iszero() ieee_functions(3M) IEEE classification
j0() bessel(3M) Bessel function
j1() bessel(3M) Bessel function
jn() bessel(3M) Bessel function
ldexp() frexp(3M) exponent adjustment
lgamma() lgamma(3M) log gamma function
log() exp(3M) natural logarithm
logb() ieee_test(3M) exponent extraction
log1p() exp(3M) log(1+X)
log2() exp(3M) log base 2
log10() exp(3M) common logarithm
matherr() matherr(3M) math library exception-handling routines
max_normal() ieee_values(3M) double-precision IEEE largest positive normalized number
max_subnormal() ieee_values(3M) double-precision IEEE largest positive subnormal number
min_normal() ieee_values(3M) double-precision IEEE smallest positive normalized number
min_subnormal() ieee_values(3M) double-precision IEEE smallest positive subnormal number
modf() frexp(3M) floating-point analysis
nextafter() ieee_functions(3M) IEEE nearest neighbor
nint() rint(3M) convert to integral value in integer format
pow() exp(3M) power X**Y
quiet_nan() ieee_values(3M) returns double-precision IEEE quiet NaN
remainder() ieee_functions(3M) floating-point remainder
rint() rint(3M) convert to integral value in floating-point format
scalb() ieee_test(3M) exponent adjustment
scalbn() ieee_functions(3M) exponent adjustment
signaling_nan() ieee_values(3M) returns double-precision IEEE signaling NaN
signbit() ieee_functions(3M) IEEE sign bit test
significand() ieee_test(3M) scalb(x,-ilogb(x))
sin() trig(3M) trigonometric function
sincos() trig(3M) simultaneous sin and cos
single_precision() single_precision(3M) single-precision libm access
sinh() hyperbolic(3M) hyperbolic function
sqrt() sqrt(3M) square root
tan() trig(3M) trigonometric function
tanh() hyperbolic(3M) hyperbolic function
y0() bessel(3M) Bessel function
y1() bessel(3M) Bessel function
yn() bessel(3M) Bessel function
Prepared by Jim Prescott and Del Armstrong

Last modifed: Thursday, 07-Apr-2011 09:24:19 EDT