       OOOOOO                            VV        VV
      OO    OO   PPPPPPP   TTTTTTTT  II   VV      VV  EEEEEE   CCCCCC
      OO    OO   PP    PP     TT     II    VV    VV   EE       CC
      OO    OO   PPPPPPP      TT     II     VV   VV   EEEEEE   CC
      OO    OO   PP           TT     II       VVV     EE       CC
       OOOOOO    PP           TT     II        V      EEEEEE   CCCCCC


                       OptiVec  Version 1.2
                         for Borland C++
                     (Version 3.0 or higher)

                      Dr. Martin Sander Software Development
                      Serturnerstr. 11
                      D-37085 Goettingen
                      Germany
                      e-mail: MartinSander@Bigfoot.com


For the commercial version, please order by e-mail or through the web-sites
http://www.atlantic-coast.com/cgi-bin/sellonline/136.htm
http://www.shareit.com/programs/101557.htm
http://www.shareit.com/deutsch/programs/101556.htm
See chapter 1.3 for details.


*****************************************************************************

F i r s t  P a r t :   File  HANDBOOK.TXT

!!     This is an ASCII text file!  It is best viewed with a simple        !!
!!     DOS editor.                                                         !!
!!     If you load this file into a word processor under Windows, you      !!
!!     must use the filter "DOS text".                                     !!
!!     Alternatively, you may use FCONVERT (shipped with Borland C++) to   !!
!!     convert from ASCII (OEM) into the ANSI character set.               !!
!!     preferably use the lettertype CourierNew 10 pt.                     !!

Brand and product names mentioned in this handbook for identification
purposes are trademarks or registered trademarks of their respective holders.

                 **************************************
   German-speaking users:
       Um die Kosten fr das Herunterladen der Shareware-Version
       ber das Internet fr alle so gering wie mglich zu halten,
       enthlt diese nur die englische Dokumentation. Sie finden
       die deutsche Beschreibung separat unter
             http://www.gwdg.de/~msander/Download/BC/VECDOCD.ZIP
                 **************************************


****************************************************************************
*                                                                          *
*******                           Contents                           *******
*                                                                          *
****************************************************************************

F i r s t  P a r t :   File  HANDBOOK.TXT

This HANDBOOK describes the main part of the OptiVec package, which
is VectorLib. The other parts, CMATH and MatrixLib, have their own
descriptions in separate files.
CMATH:     see CMATH.TXT.
MatrixLib: see MatLib.h and MFstd.h  (sorry, no handbook available with
                 this beta version of MatrixLib; the necessary information
                 is given as annotations in the include files mentioned).

1. Introduction
    1.1 What is VectorLib and Why are the VectorLib Functions so Fast?
    1.2 Licence Terms
    1.3 Registered Version
    1.4 Getting Started

2. The Elements of VectorLib Routines
    2.1 The Data Types ui,  quad,  and extended
    2.2 Complex Numbers: The Data Types fComplex,  dComplex,  eComplex
    2.3 Vectors and Arrays: The Data Types fVector, dVector, eVector,
        cfVector,  cdVector,  ceVector,   siVector, iVector, liVector,
        usVector,  uVector,  ulVector,  qiVector,  and  uiVector
    2.4 Real-number Functions: The Prefixes VF_,  VD_,  and VE_
    2.5 Complex-number Functions: The Prefixes VCF_, VCD_, and VCE_
    2.6 Functions of the Integer Data Types: The Prefixes VI_, VSI_,
        VLI_, VQI_, VU_, VUS_, VUL_, and VUI_
    2.7 Common Functions of Several Data Types: The Prefix V_

3. The Environment
    3.1 The Different Library Versions: Selecting Language, Memory Model,
        and Processor

4. VectorLib Functions and Routines: A Short Overview
    4.1 Generation, Initialization and De-Allocation of Vectors
    4.2 Index-oriented Manipulations
    4.3 Data-Type Interconversions
    4.4 More about Integer Arithmetics
    4.5 Basic Functions of Complex Vectors
    4.6 Mathematical Functions
        4.6.1 Rounding
        4.6.2 Comparisons
        4.6.3 Direct Bit-Manipulation
        4.6.4 Basic Arithmetics
        4.6.5 Powers
        4.6.6 Exponentials and Hyperbolic Functions
        4.6.7 Logarithms
        4.6.8 Trigonometric Functions
    4.7 Analysis
    4.8 Signal Processing:Fourier Transforms and Related Topics
    4.9 Statistical Functions and Building Blocks
    4.10 Input and Output
    4.11 Graphics

5. Error Handling
    5.1 General Remarks
    5.2 Integer Errors
    5.3 Floating-Point Errors
        5.3.1 Differences between Borland C++ 4.0 and earlier versions
    5.4 The Treatment of Denormal Numbers
    5.5 Advanced Error Handling: Writing Messages into a File

6. Trouble-Shooting
    6.1 General Problems
    6.2 Problems with Windows 3.x?
    6.3 Problems with the 16-bit Linker?

7. The include-files of VectorLib


S e c o n d  P a r t :  File  FUNCREF.TXT

 8.  Alphabetical Reference

 9.  Non-vectorized Functions

10. VectorLib Error Messages



****************************************************************************
*                                                                          *
*******                       1. Introduction                        *******
*                                                                          *
****************************************************************************


1.1 What is VectorLib and Why are the VectorLib Functions so Fast?
------------------------------------------------------------------

VectorLib offers a powerful library of routines for numerically demanding
applications, making the philosophy of vectorized programming available for
C/C++, Pascal, and Fortran languages. VectorLib serves to overcome the
limitations of loop management of conventional compilers - which proved to
be one of the largest obstacles in the programmer's way towards efficient
coding for scientific and data analysis applications.

Conventionally, a vector, i.e. a one-dimensional array of data of the same
type, would be processed by "dissolving" it into a loop over its elements,
leaving it to the compiler to produce efficient code. Compiled code, however,
is always far from perfect. This means that your computer is occupied with
slow and often inaccurate calculations. Now, with VectorLib, things become
easier: vectors are processed as a whole; they need no longer be dissolved
into loops. A large set of strictly typed functions is defined and realized
in a tight Assembler-written implementation.

In comparison to the old vector language APL, VectorLib has the advantage of
being incorporated into the modern and versatile languages C/C++, Pascal, and
Fortran. Recent versions of C++ and Fortran do already offer some sort of
vector processing, by virtue of iterator classes using templates (C++) and
field functions (Fortran90). Both of these, however, are basically a con-
venient means of letting the compiler write the loop for you and then compile
it to the usual inefficient code. The same is true for the popular BLAS
(Basic Linear Array Subroutine) libraries for Fortran. In comparison to
these approaches, VectorLib is superior mainly with respect to execution
speed - on the average by a factor of 2-3, in some cases even up to 8.
The performance is no longer limited by the quality of your compiler, but
rather by the real speed of the processor!

Moreover, the input and output vectors of VectorLib routines may be of
variable size and it is possible to process only a part (e.g., the first 100
elements, or every 10th element) of a vector, which is another important
advantage of the VectorLib functions over other approaches, where only whole
arrays are processed.

Using VectorLib routines instead of loops can make your source code much more
compact and far better readable.

Besides this increased efficiency and ease of programming, the wide range of
routines and functions covered by VectorLib makes this package the preferrable
programming tool for scientific and data analysis applications, competing with
many high-priced integrated systems, but imbedded into your favourite
programming language:

*   All operators and mathematical functions of C/C++ are implemented in
    vectorized form; additionally many more mathematical functions are
    included which normally would have to be calculated by more or less
    complicated combinations of existing functions. Not only the execution
    speed, but also the accuracy of the results is greatly improved.

*   Building blocks for statistical data analysis are supplied.

*   Derivatives, integrals, interpolation schemes are included.

*   Fast Fourier Transform techniques allow for efficient convolutions,
    correlation analyses, spectral filtering, and so on.

*   Graphical representation of data offers a convenient way of monitoring
    the results of vectorized calculations.

*   Each function exists for every data type for which this is reasonable.
    The data type is signalled by the prefix of the function name. No
    implicit name mangling or other specific C++ features are used, which
    makes VectorLib usable in C as well as in specific C++ programs.
    Moreover, the names and the syntax of nearly all functions are the same
    in C/C++, Pascal and Fortran languages.

*   Besides the vectorized complex functions, CMATH is included. This is a
    library of complex operations and functions designed to be a faster,
    safer and more complete replacement to the complex class libraries
    shipped with C++ compilers. Moreover, CMATH does not require C++, but
    may be used with simple C.

*   A large set of matrix operations is provided by MatrixLib, included
    in the OptiVec package.


As noted above, all functions, except some of the graphics and I/O routines,
are written in Assembly language. This made optimizations possible which are
not available in code produced by a compiler. You need not know any of the
technical details described in the following lines and you may skip them,
but perhaps these explanations will give you an idea of which performance
to expect from VectorLib.

*   Floating-point constants, which are needed in the evaluation of
    mathematical functions, are left on the floating-point number stack as
    long as they are needed. This saves a large amount of loading/unloading
    operations which are necessary if a mathematical function is called for
    each element of a vector separately.

*   Where necessary, all eight coprocessor registers are employed. (For
    present compilers, it is already an excellent achievement to master the
    book-keeping for only four coprocessor registers.)

*   The addressing of vector elements is still a major source of inefficiency
    with present compilers. Swtiching forth and back between input and output
    vectors, a large number of redundant addressing operations is performed.
    The strict (and easy!) definitions of all VectorLib functions allow to
    reduce these operations to a minimum.

*   The 32-bit operations of the 386+ and the improved coprocessor commands
    of the 387+ are consequently used. (This is why the present Shareware
    version does not run on 286 machines and not without coprocessor.)

*  For any operations with floating-point numbers that can also be performed
   using integer commands (like copying, swapping, or pushing onto the stack),
   the faster method is consistently employed.

*  C compilers convert a float into a double, before passing it to a mathe-
   matical function. This approach was useful at times when disk memory was
   too great a problem to include separate functions for each data type in
   the .LIB files stored on disk, but it is simply inefficient on modern PCs.
   Consequently, no such implicit conversions are present in the VectorLib
   routines. Here, a function of a float is calculated to float (i.e. single)
   precision, wasting no time for the calculation of more digits which would
   be discarded anyway.

*  All external function calls are eliminated from the inner loops of the
   vector processing. This saves the execution time necessary for the
   "call / ret" pairs and for loading the parameters on the stack.

*  To ensure proper parallel processing of the CPU and the floating-point
   unit, compilers have to be careful with the synchronization, adding a
   lot of "wait" statements to the program code. Within the tightly defined
   VectorLib routines, wait commands are used only where it is really
   necessary (not relevant for the Pentium processor: no "wait" needed
   at all).

*  In many cases (like, e.g., the fast integer addition in VI_addC), the
   vectors are processed in chunks of up to four elements instead of single
   ones, reducing the relative amount of time spent for loop management.

*  In addition to these vector-specific optimizations, VectorLib employs all
   optimizations you expect from good compilers, including  organization of
   the code for most efficient use with superscalar processors like the
   Pentium and its competitors.


The implementation described in this documentation refers to Borland C++,
version 3.0 or later for DOS and Microsoft Windows 3.0 or later (or Win-OS
sessions under IBM OS/2 2.0 or later; in the following, we will simply speak
of "Windows"). The library for the memory model FLAT for Windows95 and
WindowsNT requires Borland C++, version 4.0 or higher.

Depending on your choice when ordering or downloading the Shareware version,
you have got either of the following three library versions:
memory model FLAT for Windows95/NT,
             LARGE for DOS, or
             LARGE for Windows 3.x.
All of them require, at least, a 386 computer equipped with a 387
coprocessor. This means: no emulation, no 486SX, but preferably 486DX,
Pentium or higher.
The full (registered) version contains libraries for all memory models of
DOS, 16-bit Windows and 32-bit Windows. These libraries in turn are shipped
in three versions:
one for 486DX and Pentium computers, the second for 386 with 387,
the third for 286 with or without coprocessor, i.e. with emulation.

Versions for other C compilers and for Pascal, Delphi, and Fortran are in
preparation.
For two-dimensional arrays, a beta release of MatrixLib comes with VectorLib,
offering optimized operations like matrix arithmetics, algebra,
decompositions, etc.
TensorLib is planned as a future extension of these concepts for general
multidimensional arrays.


1.2 Licence Terms
-----------------

This is the English Shareware version of VectorLib for Borland C++
("SOFTWARE"). It may be used under the following licence terms:

1. You may test the SOFTWARE free of charge for an unlimited period of time.
   This testing phase ends when you permanently integrate functions of this
   SOFTWARE into any of your applications (programs, program parts...).
2. If you want to use this SOFTWARE for commercial purposes, you have
   to purchase the registered version (see chapter 1.3).
3. Use of this SOFTWARE for educational purposes at schools and universities
   remains free of charge. However, if any application created under these
   terms is sold to others or otherwise used for commercial purposes,
   paragraph 2 applies.
4. Distributing this SOFTWARE to others is allowed only in one of the
   following two ways:
   a) linked into your programs, so that the parts stemming from this
      SOFTWARE do no longer appear as a library.
   b) as a whole in unchanged form (in particular the Copyright and Licence
      statements!), whereby you may ask a fee only and exclusively for the
      physical act of copying the SOFTWARE.
5. This SOFTWARE is provided on an "as is" basis. Any explicit or implicit
   warranties for the SOFTWARE are excluded.
   Despite thorough testing of the SOFTWARE, errors and bugs cannot
   be excluded with certainty. No claims as to merchantability or fitness
   for a particular purpose are made.
   You may not use the SOFTWARE in any environment or situation where
   personal injury or excessive damage to anyone's property (including
   your own) could arise from malfunctioning of the SOFTWARE.


Copyright for the SOFTWARE and its documentation (C) 1996-1998 Martin Sander

All rights reserved, including those of translation into foreign languages.

Address of the author:
              Dr. Martin Sander Software Development
              Sertrnerstr. 11
              D-37085 Gttingen
              Germany
              e-mail: MartinSander@Bigfoot.com



1.3 Registered Version
----------------------

The full (registered) version of OptiVec

-  supports all memory models of Windows95, NT, 3.x, and DOS

-  has individually optimized libraries for each degree of processor
   backward-compatibility:
      486DX/Pentium+
      386+ (387 coprocessor required)
      286+ (no coprocessor required).

-  comes with printed documentation.

-  can be ordered at the following conditions:

   a) if you can pay in German Marks (from 1999 on: in Euro)
      and order directly from the author, the price is
      DM  399,- for  1 unit,
      DM 1399,- for  5 units,
      DM 2299,- for 10 units    (incl. 16% VAT, plus DM 10,- handling charge).
      Please order by sending an e-mail to MartinSander@bigfoot.com
      or use a print-out of the file ORDER.TXT.
      Payment options:
          - pre-paid by DM Eurocheque
          - C.O.D. (Cash-On-Delivery)
          - upon invoice (only within Germany, net 14 days)

      If you have a European VAT ID, or if you order from outside the
      European Union, you are exempt from the German VAT, but you may
      have to pay your local VAT and/or import duties according to
      local laws.

   b) International credit card or USD cheque payment is possible by
      ordering through the following web-sites:

      http://www.atlantic-coast.com/cgi-bin/sellonline/136.htm
      $ 250 for  1 unit,
      $ 800 for  5 units,
      $1500 for 10 units
      Add $5 for S&H and applicable VAT.

      http://www.shareit.com/programs/101557.htm         (English handbook)
      http://www.shareit.com/deutsch/programs/101556.htm (German handbook)
      $ 255 for  1 unit (including S&H). Add applicable VAT.

      USD prices are subject to change without notice, especially in the case
      of strong exchange-rate fluctuations. Please see the actual prices
      at the web-site mentioned.

Purchasing the full (registered) version gives you the right to use it on
as many computers at a time as the number of units you bought.
Corporate site and world-wide licences are available upon request.


1.4 Getting Started
-------------------

To install OptiVec, please follow these steps:

1.  In order to use OptiVec, you need an already installed copy of Borland
    C/C++. Install OptiVec by executing INSTALL.EXE from the root directory
    of the installation disk or CD-ROM. Normally, OptiVec will be installed
    into a sub-directory of Borland C/C++, named "OPTIVEC".

2.  Assuming your Borland C directory is C:\BC,  add
       C:\BC\OPTIVEC\LIB       to the library search path  and
       C:\BC\OPTIVEC\INCLUDE   to the include-file search path of the IDE
                               (and of the configuration file TURBOC.CFG, in
                               case you are using the command-line compiler).

3.  Choose the desired platform (DOS, Windows3.x, or Win32).
    If you chose DOS or Windows3.x, select the memory model LARGE.
    (For Win32, it is automatically FLAT).
    You should also choose 386 code generation and real coprocessor
    commands (i.e., no emulation).

4.  Add the desired OptiVec libraries to your project list.
    For DOS programs, these are
        VCL3.LIB,  MCL3.LIB, and CMATHL3.LIB.
    For Windows3.x, you need
        VCL3W.LIB, MCL3W.LIB, and CMATHL3W.LIB.
    Of course, if you do not use MatrixLib or CMATH, you do not need
    to include their libraries.
    For Win32 (Windows 95, NT), please choose
        VCF3W.LIB.
        (For the 32-bit model, CMATH and MatrixLib are integrated
         into the library VCF3W.LIB.)

5.  Use #include directives to declare VectorLib and CMATH functions by
    including the header files described in chapter 7.
    To get everything at once, declare
        #include <VecAll.h>
        #include <MatAll.h>.
    If you are writing ObjectWindows applications, any OptiVec header
    files should be included after the OWL header files.

6. 16-bit programs only:
    *   If the linker option "process extended dictionaries" is available
        in your version of Borland C++, you must switch it on.
        Otherwise, you might get a "Table limit exceeded" linker error.

    *   OptiVec works with Borland (Turbo) C++, version 3.0 or higher.
        Since, from version 4.0 on, Borland changed the name of the error
        handling routine matherr (without underbar) into _matherr (with a
        leading underbar), any 16-bit program using CMATH has to call a macro,
        NEWMATHERR, which takes  care of redirecting calls to _matherr,
        if necessary. You should place the call to NEWMATHERR into the
        module containing  main() or OwlMain():

             #include .....
             #include <VecAll.h>
             NEWMATHERR

             int main( void )
             {    ..........   }

        If you forget to call NEWMATHERR, you will get a linker error
        "Unresolved external _matherr" in the Borland C versions from 4.0 on.

        Inclusion of the macro NEWMATHERR is not needed for 32-bit programs.

After these preparations, all OptiVec functions are available for your
programs.

Should you wish to remove OptiVec from your computer after testing, please
simply delete the directory OPTIVEC with its subdirectories. The installation
of OptiVec does not affect any files outside its own directory, so there
is nothing else to get rid of.



****************************************************************************
*                                                                          *
*******               2. Elements of VectorLib Routines              *******
*                                                                          *
****************************************************************************

2.1 The Data Types ui,  quad,  and extended
-------------------------------------------

To increase the versatility and completeness of VectorLib, three additional
data types are defined in <VecLib.h>:

The data type ui (short for "unsigned index") is used for the indexing of
vectors and is defined as "unsigned int". However, in the HUGE model (sup-
ported only in the registered version of VectorLib), ui is defined as
"unsigned long", in order to correctly address huge arrays (greater than
64 kBytes!).

Starting already with the 8086/8087 processor pair, the Intel processors
are able to process integer numbers of up to 64 bits (8 bytes). We call the
64-bit type "quad" (for "quadword integer"). It is not fully supported by
Borland C++. Therefore, floating-point numbers (preferably long doubles
with their 64-bit mantissa) have to be used as intermediates. The necessary
interface functions, setquad, quadtod and _quadtold, are described in
chapter 9.
The type quad is always signed. There is not anything like an "unsigned quad".

The data type extended, which is familiar to Turbo Pascal users, is defined
as a synonym for "long double". The reason behind this is that all VectorLib
routines shall have identical names in C/C++, Pascal and Fortran languages.
Since the function prefixes are derived from the data types of the processed
vectors (see below), this necessitates the definition of alias names for some
data types denoted differently in the various languages. While the letter
"L" (which could possibly stand for "long double") is already overcrowded by
the data types long int and unsigned long, the letter "E" is unique to the
data type extended and therefore used in the prefixes for vectors and
functions of long double precision. This way, the letters defining the real-
number data types are in alphabetical proximity: "D" for double, "E" for
extended, and "F" for float. Maybe the future will bring high-precision
128-bit and 256-bit real numbers which could find their place in this series
as "G" for "great" and "H" for "hyper".



2.2 Complex Numbers:
The Data Types fComplex,  dComplex,  eComplex
---------------------------------------------

Complex numbers are treated in C/C++ in quite a confusing way. ANSI C offers
only a struct complex, Borland's C/C++ compiler additionally a struct
_complexl for complex numbers of double and long double precision, resp.
The real and imaginary parts are denoted as x and y.
C++ offers a class complex which is of double precision; the real and
imaginary parts are accessible via the functions real and imag. There is
also a number of mathematical functions available for this class.
Finally, the new Standard C++ library, included in Borland C++ 5, offers the
classes complex<float>, complex<double>, and complex<long double>, equipped
with basic functionality and the same range of mathematical functions
offered by the class complex.

Most compilers (including Borland C++, unfortunately) implement these
functions very inefficiently and inaccurately. (Just writing down the
textbook formula for a complex function, like it is usually done, works
fine only for a very limited range of arguments!)

Our aims are
*   to make the use of complex numbers of all three data types
    possible in C as well as in C++,
*   to allow for the most efficient implementation of all complex operations,
    using assembler code instead of C++ templates,
*   and to introduce an easy, compact and consistent nomenclature.

To this end, the new complex math library CMATH was created and is shipped
together with VectorLib. CMATH is described in greater detail in the file
CMATH.TXT. If you use any of the non-vectorized functions contained in CMATH,
you should include <newcplx.h> (for C++ modules) or <cmath.h> (for plain-C
modules) before (!) any of the VectorLib include files.

VectorLib itself contains the necessary initialization functions of complex
numbers and all vectorized forms of complex math functions. If you are using
only these, you need not explicitly include CMATH. In this case, the
following complex data types are defined in <VecLib.h>:
typedef  struct { float     Re,  Im; }  fComplex;
typedef  struct { double    Re,  Im; }  dComplex;
typedef  struct { extended  Re,  Im; }  eComplex;

(the data type extended is used as a synonym for long double, see above.)

If, for example, a complex number z is declared as  "fComplex  z;", the real
and imaginary parts of z are available as z.Re and z.Im, resp. Complex numbers
are initialized either by setting the real and imaginary parts separately to
the desired value, e.g.,
	z.Re = 3.0;   z.Im = 5.7;

or, alternatively, the same initialization can be accomplished by the
function fcplx:
	z = fcplx( 3.0, 5.7 );

For double-precision complex numbers, use dcplx, for extended-precision
complex numbers, use ecplx.

Pointers to arrays or vectors of complex numbers are declared using the data
types cfVector, cdVector, and ceVector  described below.



2.3 Vectors and Arrays:
The Data Types  fVector,  dVector,  eVector,  cfVector,  cdVector,  ceVector,
                siVector, iVector,  liVector,  qiVector,
                usVector, uVector,  ulVector,  and  uiVector
-----------------------------------------------------------------------------

We define, as usual, a "vector" as a one-dimensional array of data containing,
at least, one element, with all elements being of the same data type. Using a
more mathematical definition, a vector is a rank-one tensor. A two-dimensional
array (i.e. a rank-two tensor) is denoted as a "matrix", and higher
dimensions are always referred to as "tensors".

In contrast to other approaches, VectorLib does not allow zero-size vectors!

The basis of all VectorLib routines is formed by the various vector data
types given below and declared in <VecLib.h>. In your programs, you may mix
these vector types with the static arrays of classic C style.
For example:
float   a[100];           /* classic static array */
fVector b=VF_vector(100); /* VectorLib vector */
VF_equ1( a, 100 );      /* set the first 100 elements of a equal to 1.0   */
VF_equC( b, 100, 3.7 ); /* set the first 100 elements of b equal to 3.7  */

In contrast to the fixed-size static arrays, the VectorLib types use dynamic
memory allocation and allow for varying sizes. Because of this increased
flexibility, we recommend that you predominantly use the latter.
Here they are:
typedef     float *            fVector;
typedef     double *           dVector;
typedef     long double *      eVector;
typedef     fComplex *         cfVector;
typedef     dComplex *         cdVector;
typedef     eComplex *         ceVector;
typedef     short *            siVector;
typedef     int  *             iVector;
typedef     long *             liVector;
typedef     quad *             qiVector;
typedef     unsigned short *   usVector;
typedef     unsigned *         uVector;
typedef     unsigned long *    ulVector;
typedef     ui *               uiVector;

Thus, internally, a data type like fVector means "pointer to float", but
you may think of a variable declared as fVector rather in terms of a
"vector of floats". The data types ui, quad, fComplex, dComplex and eComplex
themselves are described above.

Note: in connection with Windows programs, often the letter "l" or "L" is
used to denote "long int" variables. In order to prevent confusion, however,
the data type "long int" is signalled by "li" or "LI", and the data type
"unsigned long" is signalled by "ul" or "UL".  Conflicts with prefixes for
"long double" vectors are avoided by deriving these from the alias name
"extended" and using "e", "ce", "E", and "CE", as described above and in the
following.



2.4 Real-number Functions:
    The Prefixes VF_,  VD_,  and VE_
------------------------------------

The VectorLib package supports the three floating-point data types that are
used by the coprocessors of the 80x87 family and the FPU units integrated
into the 486DX and Pentium processors and their successors:  float,  double,
and extended (i.e., long double).  BCD numbers are not supported.

Any of the algebraic and mathematical functions included in this library
exists in one variant for each floating-point format. The data type of all
floating-point vector elements, parameters, and of the return value is always
the same within one function. The data type is signalled by the second letter
of the prefix: VF_ denotes the variant of a function that uses exclusively
the data type float, VD_ stands for the data type double, and VE_ for the
data type extended, i.e., long double. (The first letter, "V", stands for
"Vector function", of course.)  VF_ functions thus work on arrays declared as
fVector, use parameters of the type float, and, if there is any floating-point
return value, this will also be of the type float. There are no mixed-type
functions (that would, e.g., work on vectors of type fVector, use parameters
of type double and return a value of type long double).

One partial exception from this rule comes from the fact that, in Borland C++,
floating-point return values are always stored as long doubles on the number
stack; if you use the option "Fast floating point" (in the IDE in the menu
"Options/Compiler/Advanced Code Generation",  or in the command-line compiler
the option "-ff"), you may assign the return value of a function to a
variable of another data type. For example, the product of all elements of a
vector may easily overflow, and it is a good idea to define   eProd  as an
extended (i.e., as a long double), before writing the line
   eProd = VF_prod( X, size );  .

For the description of the functions in the Alphabetical Reference
(chapter 8), generally only the VF_ version is described and its syntax
explicitly given. The versions for the data types double and long double
are exactly analogous to the VF_ variant. You have only to replace the
prefix  "VF_" by  "VD_" (or  "VE_") and to use  "dVector" and "double"
(or "eVector" and "extended", resp.) wherever you find "fVector" and "float"
in the VF_ version.



2.5 Complex-number Functions:
    The Prefixes VCF_, VCD_, and VCE_
--------------------------------------

Any prefix with its second letter being "C" denotes a function of complex
numbers. By analogy with the nomenclature used for real-number functions, the
prefix VCF_ signals the exclusive use of single-precision vectors, parameters
and return values (fComplex, cfVector and float). Similarly, VCD_ is used for
double-precision calculations, and VCE_ for extended precision. Wherever
"fComplex", "cfVector", and "float" appear in the description of a function in
the VCF_ version, the VCD_ and VCE_ versions are obtained by substituting with
"dComplex",  "cdVector" and "double"  or "eComplex", "ceVector", and "extended"
(or "long double"), resp.

Note: Return values of the data types fComplex, dComplex, and eComplex are
not possible in Turbo Pascal. Therefore, the syntax of those functions
returning a complex number is different in C/C++ and Turbo Pascal.

In contrast to the carelessness with which complex mathematical functions are
often treated (see above), the complex functions of VectorLib are written
such as to achieve full accuracy over the complete range of input/output
values possible with the respective data type.

In order to perform non-vectorized complex operations with the same level
of speed and reliability as the vectorized ones, use CMATH as a replacment
of the complex class libraries. See the file CMATH.TXT for details.



2.6 Functions of the Integer Data Types:
    The Prefixes VI_, VSI_,  VLI_, VQI_, VU_, VUS_, VUL_, and VUI_
------------------------------------------------------------------

The nomenclature for the integer data types is designed in a similar way as
for the floating-point data types: VI_ indicates the use of the data type
int, VSI_ stands for short int, VLI_ for long int and VQI_ for quad
integers, VU_ denotes operations with unsigned integers, VUS_ with unsigned
short and VUL_ is the prefix for functions of unsigned long arguments. For
operations on index-arrays, functions with the prefix VUI_ allow to perform
calculations using arguments of the data type ui defined above. The VUI_
versions are always defined as macros, and the compiler automatically
substitutes either the VU_ or the VUL_ version, whichever is appropriate for
the memory model actually used.

Don't be afraid of so many data types. It is one of the advantages of C
language to have them, and it is one of the disadvantages, at the same time,
that a programming style is supported which mixes all the data types until
it is no longer clear "who is who".  In all normal cases, the VI_, VLI_,
VU_, and VUI_ functions should be sufficient; but keep in mind that there
are more available in case you need them.

If present, the vectorized integer functions are always described together
with their floating-point analogues. To obtain, for example, the VI_
version, vectors of type iVector have to be substituted for those of type
fVector which are demanded by the VF_ version. In the same way, the other
versions are obtained by changing "float" and "fVector" into the desired
data type.

Like the function names themselves, also the include-files in which the
functions are declared are named according to the data type they belong to.
Thus, the declarations for the functions of the data type int are to be
found in <VIstd.h> and <VImath.h>, those of the data type unsigned long in
<VULstd.h> and <VULmath.h>, and so on.



2.7 Common Functions of Several Data Types:  The Prefix V_
----------------------------------------------------------

Several functions exist that are either used independently of any data type
or that are used to interconvert the data types. Functions like V_initPlot
and V_free belong to the first case (you have to initialize the plotting
routines regardless of the data type of the vectors you are going to plot,
and the initialization is not specific for any data type).
A function like V_ULtoD  belongs to the second case; here, a  ulVector
(a vector whose elements are of the data type unsigned long) is transformed
into a dVector (a vector whose elements are doubles).
The type-independent functions are declared in <VecLib.h> and <Vgraph.h>.
The data-type interconversion functions are declared in the include-files
belonging to the destination type (i.e. the type into which the numbers are
converted).


****************************************************************************
*                                                                          *
*******                      3. The Environment                      *******
*                                                                          *
****************************************************************************

3.1 The Different Library Versions:
    Selecting Language, Memory Model, and Processor
---------------------------------------------------

The VectorLib routines may be used both in C and in C++ programs.
Depending on your choice when ordering or downloading the Shareware version,
you got one of the following three series of libraries:
    VCF3W.LIB                            for Win32 (model FLAT of Windows95
                                         and NT),
    VCL3W.LIB + MCL3W.LIB + CMATHL3W.LIB for Windows3.x, model LARGE,
    VCL3.LIB  + MCL3.LIB  + CMATHL3.LIB  for DOS Standard or DOS Overlay,
                                         model LARGE.

The nomenclature of these libraries stems from the registered version which
supports all memory models of DOS and Windows, each with its own set of
libraries (for the three hardware configurations 486DX+, 386/387+, and 286+).
The library name "VCL3W" means: [V]ectorLib for [C]/C++, memory model [L]arge,
[3]86/387 processor or higher, for [W]indows programs. The names of the
MatrixLib libraries begin with "MC..", the CMATH libraries with "CMATH..".

As has already been noted above, this Shareware version cannot be used on
286 machines and not on computers without coprocessor. In these cases, you
would have to get, for example, the library VCL2.LIB of the registered
version.



****************************************************************************
*                                                                          *
*******           4. VectorLib Functions and Routines:               *******
*******              A Short Overview                                *******
*                                                                          *
****************************************************************************


4.1 Generation, Initialization and De-Allocation of Vectors
-----------------------------------------------------------

With VectorLib, you may use static arrays (like, for example, float a[100];)
as well as dynamically allocated ones (see chapter 2.3). We recommend,
however, that you use the more flexible vector types defined by VectorLib,
using dynamic allocation. This is described in the following sections.
After a vector has been declared (e.g., as  fVector X; ), memory has to be
allocated. When the vector is no longer needed, the memory it occupies has
to be de-allocated again. For the allocation of memory, one specific function
exists for each data type:  VF_vector,   VD_vector,  VI_vector,  and so on.
If, together with the allocation, all elements shall be initialized with 0,
VF_vector0,  VD_vector0,  VI_vector0,   etc. may be called.  To de-allocate
memory, one and the same function is used for all data types:  V_free. In
order to de-allocate several vectors with only one call, use V_nfree.
V_freeAll frees all vectors at once.

Internally, the allocated vectors are written into a table to keep track
of the allocated memory. If you try to free a vector that has never been
or is no longer allocated, you get a warning message, and nothing is freed.

You might wonder why we add still more memory allocation functions to the
already rich omnium gatherum of C and C++. The reason is that, for every
environment and every memory model, the most appropriate memory management
functions shall be selected automatically. This means that you, the user,
need not deal yourself with the various methods, but can leave this task
to VectorLib. Moreover, this makes your programs more easily portable.
(Of course, the operator "new" offers similar benefits, but it is available
only in C++. Since VectorLib shall be useable both in C and C++, it has
to include its own functions for this purpose.)

The following functions are used to initialize or re-initialize vectors that
have already been created:
VF_equ0   sets all elements of a vector equal to 0;
VF_equ1   sets them equal to 1;
VF_equC   sets them equal to a constant.
VF_equV   makes one vector a copy of another,
VFx_equV  (the "expanded" version of the equality operation) relates each
          element of a vector to the corresponding element of another
          according to the formula  Yi = a * Xi + b.

VF_ramp   fills a vector with a "ramp" according to the formula  Xi = a*i + b.
VF_random fills a vector with high-quality random numbers,
VF_noise  with white noise, and
VF_comb   with a "comb" function which, at equidistant points, equals a
          constant C and is zero elsewhere.

VF_Hanning,  VF_Parzen, and VF_Welch are special functions creating so-called
windows for use in spectral analysis (see VF_spectrum).

Complex vectors may be initialized by assigning the real and imaginary parts
separately:  VF_ReImtoC,  VF_RetoC, and VF_ImtoC. Alternatively, they may be
formed out of polar coordinates: VF_PolartoC.



4.2 Index-oriented Manipulations
--------------------------------

VF_rev       is used to reverse the ordering of the elements of a vector.
VF_reflect   sets the upper half of a vector equal to the reversed lower half.
VF_rotate    is used to rotate the ordering of the elements.
VF_insert    and
VF_delete    insert or delete an element of a vector.

VF_sort      is used for fast sorting of the elements into ascending or
             descending order. If only an index-array, but not the elements
             themselves are to be rearranged,
VF_sortind   does the job.
VF_subvector extracts a subvector from a (normally larger) vector, using a
             constant sampling interval.
VF_indpick   fills a vector with elements "picked" from another vector
             according to their indices.
VF_indput    is the complement of VF_indpick and distributes the elements of
             one vector to the sites of another vector specified by their
             indices.

Operations performed only on a sampled sub-set of elements of a vector are
provided by the   VF_subvector_...  family, where the omission mark stands
for a suffix denoting the desired operation.

VF_searchC   searches for the element of a vector that is closest to a
             pre-set value (with a parameter "mode" deciding if the closest,
             the closest larger-or-equal, or the closest smaller-or-equal
             value is chosen).
VF_searchV   does the same for a whole array of pre-set values.

Polynomial, rational, and cubic-spline interpolations are performed by
VF_polyinterpol,  VF_ratinterpol, and VF_splineinterpol, resp.



4.3 Data-Type Interconversions
------------------------------

The first thing that has to be said about the floating-point data-type
interconversions is: do not use them too extensively. Decide which accuracy
is appropriate for your application, and then use consistently either the
VF_, or the VD_, or the VE_ version of the functions you need. Nevertheless,
every data type can be converted into every other, in case it is necessary.

The functions used for the interconversion of the real-value floating-point
data types are: V_FtoD,  V_DtoF,  V_FtoE,  V_EtoF,  V_DtoE,  and V_EtoD.
Similarly, the following functions are offered for the complex floating-
point data types: V_CFtoCD,  V_CDtoCF,  V_CFtoCE,  V_CEtoCF,  V_CDtoCE,  and
V_CEtoCD.

Corresponding to the large number of integer data types, there is an even
larger number of functions interconverting them. Switching between "normal",
short, long and "quadruple" integers is performed by V_ItoLI,  V_ItoQI,
V_ItoSI,  V_SItoI,  V_SItoLI,  V_SItoQI,  V_LItoSI,  V_LItoI,  V_LItoQI,
V_QItoSI,  V_QItoI,  and V_QItoLI.

Similarly, the available types of unsigned numbers are interconverted by
V_UtoUL,  V_UtoUS,  V_UtoUI,  V_UStoU,  V_UStoUL,  V_UStoUI,  V_ULtoUS,
V_ULtoU,  V_ULtoUI, V_UItoU,  V_UItoUS,  and V_UItoUL.

Interconversions between signed and unsigned types can only be performed on
the same level of accuracy, namely by the functions V_ItoU,  V_UtoI,  V_LItoUL,
V_ULtoLI,  V_SItoUS,  and V_UStoSI.  That means that functions like V_UStoLI
do  n o t  exist!

The conversion of integers into floating-point types is accomplished by
V_ItoF,  V_ItoD,  V_ItoE,  V_SItoF,  V_SItoD,  V_SItoE,  V_LItoF,  V_LItoD,
V_LItoE,  V_QItoF,  V_QItoD,  V_QItoE,  V_UtoF,  V_UtoD,  V_UtoE,  V_UStoF,
V_UStoD,  V_UStoE,  V_ULtoF,  V_ULtoD,  V_ULtoE,  V_UItoF,  V_UItoD,   and
V_UItoE. Again, do not be confused by the large number of these functions,
but keep only in mind that for every interconversion there is one available.

The reverse process, the conversion of floating-point numbers into integers,
is more complicated: although every integer (except for extremely large
ones) has an exact representation in the floating-point types, this is not
true the other way round: floating-point numbers may by definition contain
fractional, i.e. "non-integer" parts. By choosing the appropriate rounding
function, the user has to decide how to treat these fractional parts:
Neglect them ("chop" or "trunc"), round to the nearest whole number ("round"),
round to the next greater-or-equal integer ("ceil") or to the next smaller-or-
equal integer ("floor"). These options are treated as mathematical functions
and are described in chapter 4.6.1.



4.4 More about Integer Arithmetics
----------------------------------

Although the rules of integer arithmetics are quite straightforward, it
appears appropriate to recall that all integer operations are implicitly
performed modulo 2**n, where n is the number of bits the numbers are
represented with. This means that any result, falling outside the range of
the respective data type, is made to fall inside the range by loosing the
highest bits. The effect is the same as if as many times 2**n had been added
to (or subtracted from) the "correct" result as necessary to reach the legal
range.
For example, in the data type short, the result of the multiplication 5 *
20000 is  -31072. The reason for this seemingly wrong negative result is
that the "correct" result, 100000, falls outside the range of short numbers
which is -32768 <= x <= +32767.  short integers are 16-bit numbers, so n = 16,
and 2**n = 65536. In order to make the result fall into the specified range,
the processor "subtracts" 2 * 65536 = 131072 from 100000, yielding -31072.

Note that overflowing intermediate results cannot be "cured" by any following
operation. For example, (5 * 20000) / 4 is not (as one might hope) 25000,
but rather -7768.

Note furthermore that the 64-bit data type quad does not employ this implicit
modulo 2**n-arithmetics. Overflow conditions lead to undefined results.



4.5 Basic Functions of Complex Vectors
--------------------------------------

The following functions are available for the basic treatment of complex
vectors.
VF_ReImtoC      forming a complex vector out of its real and imaginary parts,
VF_RetoC        overwriting the real part,
VF_ImtoC        overwriting the imaginary part,
VF_CtoReIm      extracting the real and imaginary parts,
VF_CtoRe        extracting the real part,
VF_CtoIm        extracting the imaginary part,
VF_PolartoC     forming a complex vector out of polar coordinates,
VF_CtoPolar     transforming a complex vector into polar coordinates,
VF_CtoAbs       calculating the absolute value (the magnitude of the pointer
                in the complex plane),
VF_CtoArg       calculating the argument (the angle of the pointer in the
                complex plane),  and
VF_CtoNorm      calculating the norm (which is defined here as the square of
                the absolute value).



4.6 Mathematical Functions
--------------------------

Lacking a more well-founded definition, we denote as "mathematical" all
those functions which calculate each single element of a vector from the
corresponding element of another vector by a more or less simple
mathematical formula:  Yi = f( Xi ).   Except for the "basic arithmetics"
functions, they are defined only for the floating-point data types. Most of
these mathematical functions are vectorized versions of ANSI C functions or
derived from them. Errors are handled by _matherr and _matherrl.  In
addition to this error handling "by element", the return values of the
VectorLib math functions show if all elements have been processed
successfully. If so, the return value is 0, otherwise it is any non-zero
int number.  (We do not yet use the newly introduced data type bool for
this return value, in order to make VectorLib compatible also with older
versions of Borland C.)


4.6.1 Rounding
--------------

As noted in connection with data-type interconversions, the conversion of
floating-point numbers to integer data types may be accomplished by four
different ways: Fractional parts may be neglected (VF_chop, VF_trunc), or
the numbers may be rounded to the nearest integer (VF_round),  to the next
greater-or-equal integer (VF_ceil), or to the next smaller-or-equal integer
(VF_floor).

The result of the rounding operation thus specified may either be left in
the original floating-point format, e.g., in VF_round, or it may be converted
into one of the integer types, as in VF_roundtoI,  VD_ceiltoLI, VF_choptoSI,
or VE_floortoQI. As long as the input numbers are positive, they can also be
rounded to the unsigned integer types,  as in VF_floortoU, VF_ceiltoUS,
VD_choptoUL, or VE_trunctoUI.



4.6.2 Comparisons
-----------------

Functions performing comparisons are generally named VF_cmp... (where
further letters and/or numbers specify the type of comparison desired).
Every element of a vector can be compared either to 0, or to a constant C,
or to the corresponding element of another vector. There are two
possibilities: either the comparison is performed with the three possible
answers "greater than", "equal to" or "less than". In this case, the results
are stored as floating-point numbers (0.0,  1.0,  or -1.0). Examples are
VF_cmp0,  VD_cmpC,  and VE_cmpV.

The other possibility is to test if one of the following conditions is
fulfilled: "greater than", "greater than or equal to", "equal to", "not
equal to", "less than", or "less than or equal to". Here, the answers will
be "TRUE" or "FALSE" (1.0 or 0.0). Examples are VF_cmp_eq0,  VD_cmp_gtC, and
VE_cmp_leV.

Alternatively, the indices of the elements for which the answer was "TRUE"
may be stored in an index-array, as in VF_cmp_neCind, VD_cmp_lt0ind,  and
VE_cmp_geVind.

To test if (at least) one element of a table is equal to a preset value, the
function VF_iselementC may be used. In order to test for each element of a
vector, if it has an identical entry in a table, VF_iselementV should be
used.



4.6.3 Direct Bit-Manipulation
-----------------------------

For the integer data types, a number of bit-wise operations is available:
VI_shl and VI_shr shift the bits to the left or to the right, resp., which
is used for the fast multiplication and division by integer powers of 2.
The principal use of VI_and is the fast modulo division of positive or
unsigned numbers, while VI_or,  VI_xor, and VI_not  will find use only in
special applications.



4.6.4 Basic Arithmetics
-----------------------

In the following list, only the VF_ function is explicitly named, but the
VD_ and VE_ functions exist as well; if it makes sense, the same is true for
the complex and for the integer-type versions:

VF_neg        Yi = - Xi;
VF_abs        Yi =  Xi ;
VCF_conj      Yi.Re = Xi.Re; Yi.Im = -(Xi.Re).
VF_inv        Yi = 1.0 / Xi;
VF_equC       Xi = c;                VF_equV     Yi = Xi;
VF_addC       Yi = Xi + c;           VF_addV     Zi = Xi + Yi;
VF_subC       Yi = Xi - c;           VF_subV     Zi = Xi - Yi;
VF_subrC      Yi = c - Xi;           VF_subrV    Zi = Yi - Xi;
VF_mulC       Yi = Xi * c;           VF_mulV     Zi = Xi * Yi;
VF_divC       Yi = Xi / c;           VF_divV     Zi = Xi / Yi;
VF_divrC      Yi = c / Xi;           VF_divrV    Zi = Yi / Xi;
VF_modC       Yi = Xi mod c;         VF_modV     Zi = Xi mod Yi.

Besides these basic operations, several frequently-used combinations of
addition and division have been included, not to forget the Pythagoras
formula:

VF_hypC    Yi = Xi / (Xi + c);        VF_hypV    Zi =  Xi / (Xi + Yi);
VF_redC    Yi = (Xi * c) / (Xi + c);  VF_redV    Zi =  (Xi * Yi) / (Xi + Yi);
VF_visC    Yi = (Xi - c) / (Xi + c);  VF_visV    Zi =  (Xi - Yi) / (Xi + Yi);
VF_hypotC  Yi = sqrt( Xi + c );     VF_hypotV	 Zi =   sqrt( Xi + Yi).

All functions in the right column of the above two sections also exist in an
expanded form (with the prefix VFx_...) in which the function is not
evaluated for Xi itself, but for the expression (a * Xi + b),  e.g.,
VFx_addV:   Zi  =  (a * Xi + b) + Yi.

The simple algebraic functions exist also in yet another special form,
with the result being scaled by some arbitraty factor. This scaled
form get the prefix VFs_.
VFs_addV     Zi = C * (Xi + Yi);
VFs_subV     Zi = C * (Xi - Yi);
VFs_mulV     Zi = C * (Xi * Yi);
VFs_divV     Zi = C * (Xi / Yi);

VF_maxC     sets Yi equal to Xi or C, whichever is greater;
VF_minC     chooses the smaller of Xi and C;
VF_maxV     (and  VF_minV) set Zi equal to Xi or Yi, whichever is greater
            (or smaller, resp.).
VF_limit    limits the range of values, while
VF_flush0   sets all values to zero which are below a preset threshold.
VF_intfrac  splits the numbers into their integer and fractional parts;
VF_mantexp  splits the numbers into their mantissa and exponent parts.

In its geometrical interpretation, a vector is a pointer, with its elements
representing the coordinates of a point in n-dimensional space. There are a
few functions for geometrical vector arithmetics, namely
VF_scalprod,  which calculates the scalar product of two vectors,
VF_xprod,     which calculates the cross-product (or vector product) of two
              vectos, and
VF_Euclid,    calculating the Euclidean norm of a vector.



4.6.5 Powers
------------

VF_square,  VF_cubic, and VF_quartic, along with their expanded versions
VFx_square,  VFx_cubic,  and VFx_quartic, are used to calculate the second,
third and fourth power of the elements of the input vector. Arbitrary
integer powers are available by VF_ipow; fractional powers are calculated by
VF_pow. Polynomials are evaluated by VF_poly.

All these functions raise arbitrary numbers to specified powers, whereas the
following group of functions is used to raise specified numbers to arbitrary
powers: VF_pow10, VF_ipow10,  VF_pow2,  and VF_ipow2  raise 10 or 2, resp.,
to the (fractional or integer) powers specified in the input vector.
The exponential function, VF_exp, raises Euler's constant e to the powers
specified in the input vector. Finally, VF_expArbBase calculates the
exponential function of an arbitrary base.
The square-root, which corresponds to a power of 0.5,  is available with
VF_sqrt.

The corresponding functions for complex numbers are VCF_square,  VCF_cubic,
VCF_quartic,  VCF_ipow,  VCF_pow,  VCF_exp,  VCF_expArbBase, and VCF_sqrt.



4.6.6 Exponentials and Hyperbolic Functions
-------------------------------------------

A variety of functions are derived from the exponential function VF_exp (which
itself has already been mentioned in the last section).
VF_expc   calculates the complementary exponential function Yi = 1 - exp[Xi].
VF_expmx2 calculates the exponential function of the negative square of the
          argument,  Yi = exp[ - Xi ]. This is a bell-shaped function similar
          to the Gaussian distribution function which itself is available as
VF_Gauss.

The vectorized hyperbolic sine, cosine, tangent, cotangent, secant, and
cosecant functions are available as VF_sinh, VF_cosh, VF_tanh, VF_coth,
VF_sech, and VF_cosech. Because of its importance in physics, the squared
hyperbolic secant is also available as VF_sech2.

For complex numbers,  VCF_sinh,  VCF_cosh,  and VCF_tanh are available.



4.6.7 Logarithms
----------------

           The decadic logarithm (i.e., the logarithm to the basis 10) is
           available as
VF_log10,  the natural logarithm (i.e., to the basis e) is obtained by
VF_log,    and the binary logarithm (i.e., to the basis 2) is implemented as
VF_log2.   Similarly, for complex numbers,
VCF_log,  VCF_log10, and VCF_log2  (as always with their VCD_ and VCE_
           counterparts) are included.



4.6.8 Trigonometric Functions
-----------------------------

The vectorized sine, cosine, tangent, cotangent, secant, and cosecant
functions are available as
VF_sin,       VF_cos,
VF_sincos     (sine and cosine at once!),
VF_tan,       VF_cot,
VF_sec,       and VF_cosec.

The squares of the trigonometric functions are available by
VF_sin2,      VF_cos2,
VF_sincos2    (again both the sin and the cos at once),
VF_tan2,      VF_cot2,
VF_sec2,      and VF_cosec2.

A very efficient way to calculate the trigonometric functions for arguments
representable as rational multiples of Pi is supplied by the trigonometric
functions with the suffix "rpi" (meaning "rational multiple of p"):
VF_sinrpi, VF_cosrpi, VF_sincosrpi, VF_tanrpi, VF_cotrpi, VF_secrpi, and
VF_cosecrpi.
More specialized versions use tables to obtain frequently-used values;
these versions are denoted by the suffixes "rpi2" (multiples of Pi divided
by an integer power of 2) and "rpi3" (multiples of Pi over an integer
multiple of 3). Examples are VF_sinrpi2 and VF_tanrpi3.

The sinc function (quotient of the sine of an argument and the argument
itself) is available as the VF_sinc.

Vectorized inverse trigonometric functions are available as VF_asin,
VF_acos, VF_atan, and VF_atan2.

Complex trigonometric and inverse trigonometric functions are implemented as
VCF_sin,  VCF_cos,  VCF_tan,  VCF_asin,  VCF_acos,  and VCF_atan.



4.7 Analysis
------------

Global maxima and minima of real functions are detected by VF_max and
VF_min, resp. The same extrema, along with the index of their first
occurrence, are detected by VF_maxind and VF_minind, resp. To find the
maxima and minima in terms of absolute values, the functions VF_absmax and
VF_absmin are included along with the versions additionally yielding the
index, VF_absmaxind and VF_absminind. The "running" maximum and minimum
(where each element is set to the largest/smallest value occurring up to its
own index) are calculated by VF_runmax and VF_runmin, resp.

For complex numbers, the maximum real and imaginary parts may be found
separately by VCF_maxReIm, with the analogous function for the minima being
VCF_minReIm. For the separately-found maxima and minima of the real and
imaginary parts in absolute terms, use VCF_absmaxReIm and VCF_absminReIm.
Note that, for these four functions, the real and imaginary parts of
the result generally stem from different elements of the vector.

The largest absolute value (magnitude) occurring in a set of complex data is
found by VCF_absmax, the smallest one by VCF_absmin. To find the index of
the element with the largest/smallest magnitude along with that magnitude,
use VCF_absmaxind and VCF_absminind, resp.

The sum of all elements of a real or complex vector is available by VF_sum
and its higher-accuracy or complex analogues, the product by VF_prod and the
sum-of-squares by VF_ssq.  VF_rms determines the r.m.s. of all elements of
a vector.
Similarly to the "running" maximum, the running sum and product are available
by VF_runsum and VF_runprod, resp.

The derivative of a Y-array with respect to an X-array is calculated by
VF_derivV. If the intervals between the X-values are constant, the values
themselves are not needed for taking the derivative, but only the spacing is
required; VF_derivC should be employed in this case.
The integral of a Y-array over an X-array is calculated by the two functions
VF_integralV and VF_runintegralV, of which the first one determines only the
area under the curve defined by the input array, whereas the second one
calculates the point-by-point integral array. As for the derivative, also for
the integral the X-values themselves are not needed if they are equally-
spaced; in this case, VF_integralC and VF_runintegralC should be used.

VF_ismomoton   tests if an array is monotonously rising or falling.
VF_smooth      (which removes high-frequency noise),
VF_iselementC  (which tests, if a given value occurs within a vector), and
VF_searchC     (which searches an ordered table for the entry whose value
               comes closest to a preset value C) have to be mentioned as
               functions sometimes needed in connection with analysis.



4.8 Signal Processing:
    Fourier Transforms and Related Topics
-----------------------------------------

The forward and the backward Fast Fourier Transform (FFT) are calculated by
VF_FFT or, for complex vectors, by VCF_FFT.

Based on FFT, convolution and deconvolution are available by
VF_convolve and VF_deconvolve.
Spectral filtering is achieved by VF_filter,
spectral analysis by VF_spectrum.
The autocorrelation function of a data array is obtained by VF_autocorr,
and the cross-correlation function of two arrays by VF_xcorr.

The FFT algorithm chosen for this PC implementation is a radix-2
Cooley-Tukey routine. Only for this radix-2 algorithm, the restricted
number of eight coprocessor registers still allows to hold all inter-
mediate results of the inner transform loop in coprocessor registers.
Although featuring savings in the number of multiplications, radix-4 and
radix-8 routines are rendered less efficient than the routine chosen by
the need of storing intermediate results in memory.

There are two different versions of all FFT-based functions. Depending
on the memory model, either of the two is automatically chosen. You
may, however, explicitly specify the one you wish to employ.
The first one uses the already-mentioned table of sine values (see
chapter 4.6.8. and the function VF_sinrpi2) as a look-up table for the
Fourier coefficients needed. This table needs up to 10 kBytes.
By default, this very fast variant is used in the memory models COMPACT
and LARGE. To explicitly specify it in the other memory models, please use
the prefixes VFl_, VDl_, VEl_ (with the letter "l" for the "larger" amount
of memory needed). 

The second variant, which is automatically chosen in all memory models
except for COMPACT and LARGE, employs trigonometric recursions to obtain the
sine and cosine values with still satisfactory speed, though this procedure
is not as fast as simply reading them from a table. You may explicitly
specifiy this variant by adding the letter "s" (for the "smaller" amount of
memory needed) in the function prefix. Examples are VFs_FFT, VDs_convolve,
VEs_spectrum.
If you decide to use this variant in order to economize memory in the models
COMPACT and LARGE, use the prefix VFs_ for all(!) routines employing FFT.
Otherwise, you will not only load the look-up table, but also a second FFT
routine into your already overcrowded memory.

Although it does not use Fourier transform methods, VF_smooth should be
remembered here as a crude form of frequency filtering which removes high-
frequency noise.



4.9 Statistical Functions and Building Blocks
---------------------------------------------

The mean (or average) of all the elements of a vector is obtained by
VF_mean; if different weights are to be attributed to the individual
elements, VF_meanwW ("mean with weights") may be used. The variance of a
distribution with respect to a preset constant value is calculated by
VF_varianceC (with weights by VF_varianceCwW), the variance with respect to
another array by VF_varianceV and VF_varianceVwW. To obtain the mean and the
variance of a distribution simultaneously, VF_meanvar and VF_meanvarwW are
used.

The median of a distribution is found by VF_median.

The linear correlation coefficient of two distributions is available by
VF_corrcoeff.
VF_ssqdevC   yields the "sum of the squares of the deviations from a preset
             constant",  sum( (Xi - C) ),
VF_ssqdevV   the "sum of the squares of the deviations from another vector",
             sum( (Xi - Yi) ).
             The chi-square merit function is calculated by
VF_chi2.

The "average deviation from a preset constant",    1/N * sum( Xi - C ),
is given by VF_avdevC,
the "average deviation from another vector",  1 / N * sum( Xi - Yi ),
by VF_avdevV.

A linear regression is performed on X-Y data by VF_linregress or, if the
individual data points are to be weighted, by VF_linregresswW.

Fitting of data sets to arbitrary functions is available in MatrixLib,
which contatins the functions VF_polyfit, VF_linfit, VF_nonlinfit,
VF_multiLinfit, and VF_multiNonlinfit (see the documentation of MatrixLib).

VF_distribution bins data into a discrete one-dimensional distribution
function.

In connection with statistics, the functions VF_sum, VF_prod, VF_ssq,
VF_rms, and VF_iselementC should be remembered.



4.10 Input and Output
---------------------

There are several ways of printing the elements of a vector:
VF_cprint   prints them to the screen (or "console" - hence the "c" in the
            name) into the current text window, automatically detecting its
            height and width. After printing one page, the user is prompted
            to continue.
VF_print    is similar to VF_cprint in that the output is directed to the
            screen, but there is no automatic detection of the screen data;
            a default linewidth of 80 characters is assumed, and no division
            into pages is made.
            Both VF_print and VF_cprint should not be used within TurboVision.
            VF_cprint is not available under Windows. VF_print is available
            for DOS and EasyWin applications, but not for genuine (i.e., OWL)
            Windows programs.
VF_fprint   prints a vector to a stream. This may be a file, a printer, or
            again the screen. Nothing will prevent you from mis-using this
            function for printing to the screen in TurboVision or Windows,
            but you should not!
            VF_fprint is available in any environment (DOS, EasyWin and OWL).

VF_write   writes data in ASCII format in a stream
VF_read    reads a vector from an ASCII file.
VF_nwrite  writes n vectors of the same data type as the columns of a table
           into a stream.
VF_nread   reads the columns of a table into n vectors of the same type.

VF_setWriteFormat, VF_setWriteSeparate and VF_setNWriteSeparate allow
to modify the standard settings of VF_write and VF_nwrite.
For the whole-number variants of the ..read functions, a radix different
from the standard of 10 may be defined using V_setRadix.
V_setRadix does, however, not act on VQI_read.

VF_store and VF_recall are employed to store and retrieve data in binary
format (which is much faster and occupies fewer bytes of disk space than
ASCII format).



4.11 Graphics
-------------

We have no ambition of providing a specialized graphics package. There are
several excellent ones on the market. Nevertheless, some graphics functions
have been included that allow a quick glance on vectors.

Before any of the following functions may be used, the vector graphics has
to be initialized. For DOS programs, this is done by V_initGraph. By calling
V_initGraph, the BGI functions (on which VectorLib's graphics functions rely)
are automatically initialized, too. Do not call initgraph after V_initGraph.
If you have already called initgraph, do not use V_initGraph, but V_initPlot
instead of it. At the end of the graphics session, the Borland C++ function
closegraph has to be used to leave the graphics mode and to release graphics
buffer memory.

For Windows programs, VectorLib graphics has to be initialized by V_initPlot.
No shut-down is needed at the end, since the Windows graphics functions always
remain accessible.

V_initPlot automatically reserves a part of the screen for plotting
operations. This part comprises about 2/3 of the screen on the right
side. Above, one line is left for a heading. Below, a few lines are
left empty. To change this default plotting region, call V_setPlotRegion
after V_initPlot.

Only under Windows, all VectorLib plotting functions may directly be
used for printing on a printer. If this is desired, you have to call
V_initPrint instead of V_initPlot. By default, one whole page is
reserved for plotting. In order to change this, call V_setPlotRegion
after V_initPrint.

VectorLib distinguishes between two sorts of plotting functions,
AutoPlot  and  DataPlot.

All AutoPlot functions (e.g., VF_xyAutoPlot) execute the following steps:
*   switch into graphics mode (DOS only)
*   clear the screen (DOS: full screen; Windows: part of the screen needed
    for plotting)
*   reset all graphics settings to their defaults (color, text style,
    viewport, etc.) (DOS only)
*   define a suitable viewport
*   generate a Cartesian coordinate system with suitably scaled and labeled
    axes
*   plot the data according to the parameters passed to the function

All DataPlot functions (e.g. VE_yDataPlot) execute only the last of these
steps. They assume that a coordinate system already exists from a previous
call to one of the AutoPlot functions. The new plot is added to the existing
one. All settings of this coordinate system have to be valid. The viewport
must still be the active one and the scaling of the axes has to fit also for
the new data plot.

Since all AutoPlot functions clear the screen and all DataPlot functions
demand an unchanged viewport, additional text can be inserted only after
completion of the plot. To add text, one has to define a new viewport. Use
setviewport (DOS), SetViewportOrg (Windows with OWL 1.0), or
SetViewportOrgEx (Windows with OWL 2.0 or higher).
To switch back into text mode in DOS, use restorecrtmode. Calling one of
the AutoPlot functions brings you back into graphics mode without further
initializations being necessary.

VF_xyAutoPlot   displays an automatically-scaled plot of an X-Y vector pair.
VF_yAutoPlot    plots a single Y-vector, using the index as X-axis.
VF_xy2AutoPlot  and
VF_y2AutoPlot   plot two X-Y pairs or two Y-vectors at once, doing the
                necessary scaling so that both fit into the same coordinate
                system.
                To plot additional arrays into an already existing coordinate
                system,
VF_xyDataPlot   and
VF_yDataPlot    should be used, as has already been mentioned.

Complex arrays are printed into the complex plane (the imaginary parts
versus the real parts), using
VCF_autoPlot,  VCF_2AutoPlot,  and  VCF_dataPlot.

The different plot styles, regarding symbols, lines, and colors, are
described in connection with VF_xyAutoPlot in the Function Reference
(file FUNCREF.TXT, chapter 8).



****************************************************************************
*                                                                          *
*******                     5. Error Handling                        *******
*                                                                          *
*****************************************************************************

5.1 General Remarks
-------------------

There are generally two types of error handling: by the hardware, or by the
software. In order to prevent uncontrolled program crash, it is highly
desirable that conditions, leading to hardware errors, be recognized before
the errors actually occur. All high-level computer languages support this
software error-handling to various degrees of perfection. Within the
tightly-defined functions and routines of this VectorLib package, often an
even more efficient error handling by the program itself is possible than
provided by the compilers for user-written code.

However, it should be noted that no absolute overflow protection is possible
for the long double versions. They do not have a "safety margin" left as in
the float and double versions, where internally all calculations are performed
in extended precision. Especially the VEx_ and VCEx_versions may fail if
constant parameters are very large, or if the X vector elements themselves are
already near the overflow limit. To be on the safe side, constant parameters
should not exceed about 1.E32 for float, 1.E150 for double, and 1.E2000 for
extended parameters.

In the "expanded" versions of all functions with extended accuracy (those
with the prefixes VEx_  and VCEx_;  for example VEx_exp), there is generally
no overflow protection for the calculation of A*Xi+B, but only for the core
of the function itself and for the final multiplication by C.

A series of identical errors occurring within one and the same VectorLib
function leads to one error message only. Subsequent identical messages are
suppressed.

There is a fundamental difference between floating-point and integer numbers
with respect to OVERFLOW and DOMAIN errors: for floating-point numbers,
these are always serious errors, whereas for integer numbers, by virtue of
the implicit modulo-2**n arithmetics, this is not necessarily the case. In the
following two paragraphs, details are given on the error handling of integer
and floating-point numbers, respectively.



5.2 Integer Errors
------------------

The only genuine integer errors are ZERODIVIDE errors (if a division by 0 is
attempted). Other integer errors are neglected due to the implicit definition
of integer operations to be done modulo the respective power of 2 (see
chapter 4.4). For those situations in which implicit modulo 2**n arithmetics
is not appropriate, VectorLib offers the possibility to trap these errors and
print an error message and/or abort the program. All functions where
INTEGER OVERFLOW (e.g., in VI_ramp, VI_mulV, etc.) or INTEGER DOMAIN errors
(e.g., in V_ItoU for negative X-values) may occur, exist in two versions:
the "normal" version employs modulo 2**n arithmetics and interchanges signed
and unsigned data types according to their bit pattern.

The other version also employs modulo 2**n arithmetics, but detects the
errors. To choose this version, the symbolic constant V_trapIntError must be
defined before(!) <VecLib.h> appears in the program header.

The action taken in case of INTEGER OVERFLOW errors is then defined by a call
to the function  V_setIntErrorHandling  with one of three possibilities as
the argument (defined as enum V_ihand in <VecLib.h>):

ierrNote      print an error message
ierrAbort     print an error message and exit the program
ierrIgnore    ignore the problem. With this last option, the error handling
              can be switched off intermediately.

Example:
    #define V_trapIntError 1
    #include <VIstd.h>
    #include <VImath.h>
    .....
    main()    /*   or WinMain(),  or OwlMain()   */
    {
        iVector  I1, I2;
        I1 = VI_vector( 1000 );  I2 = VI_vector( 1000 );
        V_setIntErrorHandling( ierrNote );
        VI_ramp( I1, 1000, 0, 50 );   /* an overflow will occur here! */
        V_setIntErrorHandling( ierrIgnore );
        VI_mulC( I2, I1, 1000, 5 );
            /* here, even a whole series of overflows will occur; they are
               all ignored. */
         ....
    }



5.3 Floating-Point Errors
-------------------------

In order to understand the details of the floating-point error handling
outlined in the following sections, you may wish to refer to the description
of the functions _matherr and signal in the documentation of Borland C++
(prior to the version 4.0, instead of _matherr() the function matherr() -
without the leading underbar - was used, see below).  Keep in mind that
_matherr and _matherrl are the user-definable focal points for the handling
of all software-detected errors, whereas signal is used to install a handler
for hardware-detected errors (which should better be avoided in the first
place). Within the VectorLib functions, _matherr is used for the error
handling in the VF_, VCF_, VD_, and VCD_ versions, and _matherrl is used
in the VE_ and VCE_ versions.

Below, the possible types of errors are described. Here, we denote by
"HUGE_VAL" the largest number possible in the respective data type,
i.e. MAX_FLT, MAX_DBL, or MAX_LDBL. Similarly, "TINY_VAL" is the smallest
denormal number representable in the respective data type. This is not the
same as MIN_VAL, which is the smallest full-accuracy number of the respective
data type.

If the function in which an error occurs has one real-valued argument, only
the parameter e->x is defined in calling _matherr and e->y  is left undefined.
Only if there are two arguments (like in VF_atan2  or in VF_cotrpi),
both e->x  and e->y are needed to hold these arguments. For complex arguments,
the real part is stored in e->x  and the imaginary part in e->y.

For each function of the VectorLib package, the types of errors that are
detected and handled are described in the "Alphabetical Reference" (chapter 8).
All functions derived from ANSI C functions of the mathematical libraries
(those whose declarations are to be found in <math.h>)  contain a fully-
fledged mathematical error handling. In addition to the error handling
"by element", their return value shows if all elements have been processed
error-free (return value 0) or if an error occurred and was handled (return
value different from 0).

DOMAIN errors most often lead to the result NAN ("not-a-number"). Even if
    nothing happens within the function itself that detects a DOMAIN error,
    an uncontrolled program crash may result if subsequent operations are
    performed on the vector element set to NAN. We therefore recommend to
    modify _matherr and _matherrl in such a way that the program is aborted
    if a DOMAIN error occurs (for an example, see below; alternatively, the
    UNIX style may be adopted; see the file MATHERR.C supplied with the
    Borland C/C++ package). Changing the return value of _matherr is another
    possiblity, but the better way very clearly is to avoid any DOMAIN errors
    by performing appropriate checks before calling functions like VF_sqrt,
    VF_log, VF_atan2 etc.
       Note:  the pseudo-numbers INF and NAN are not allowed as input for any
       functions of the VectorLib library. They are not tested for; their
       presence will normally result in a hardware interrupt.

SING errors are treated like an extreme case of OVERFLOW (see below). In
    most cases, they arise from an implicit division by zero or from taking
    the logarithm of zero. The proposed result is never NAN, but always a
    "number", in most cases HUGE_VAL. Although it is recommended also in the
    case of SING errors to abort the program and take the necessary measures
    to avoid them, you may choose to continue program execution.

OVERFLOW errors are the most abundant form of floating-point errors. They
    are always handled by proposing +HUGE_VAL or -HUGE_VAL as the result.
    Within many user algorithms, OVERFLOW  errors may occur for intermediate
    results; if subsequent steps perform operations like taking the inverse,
    the final result may be acceptable despite the error. Therefore, we
    recommend to accept the return-value proposal and not to abort the
    program.

In principle, you may decide not to accept the return-value proposal of
_matherr, but to substitute another one. However, for several reasons
you are discouraged from doing that: the correct sign of the result is
set by the calling ("complaining") function in many cases only after
returning from _matherr;  the x-value passed to _matherr (which should
be inspected before the return value is modified) may either be X[i]
or (as in some of the expanded complex math functions of the VCEx_...
family) the intermediate result x' = Ax + B.  Note, furthermore, that
all x-values are passed to _matherr as double-precision floating-point
numbers, also in the case of integer input numbers (like in VF_tanrpi,
where P[i] and q are passed as x and y to _matherr).

TLOSS  ("total loss of precision") errors are handled by  _matherr only if a
    more serious error might occur in the respective function. For example,
    the sine function takes on values between -1 and +1 for all arguments.
    So, in case of an argument too big for the sine function to be evaluated
    with any accuracy, the result may nevertheless be "tacitly" set to 0.0
    and no call to _matherr is generated (whereas Borland C++ chooses NAN,
    "not a number", as the result, which is certainly even less correct than
    arbitrarily choosing 0.0).
    On the other hand, the cosecant, i.e. the inverse of the sine, is not
    defined for arguments of integer multiples of Pi. Therefore, a more
    serious error (in this case a SING or an OVERFLOW error) might be hidden
    under the TLOSS for very big arguments. This possibility is taken into
    account by calling _matherr, although the proposed result is again set
    to 0.0 (which is the mean of the two extremes +HUGE_VAL and -HUGE_VAL).
    Generally, the default result in the case of a TLOSS error is the mean of
    the results for arguments of +0.0 and -0.0.

UNDERFLOW errors are never detected; underflowing results are always
    "tacitly" set to denormal numbers or finally to 0.0 by the floating-point
    processor itself. Indeed, you may very rarely wish to do something else
    in this case.

As in all non-vectorized math functions of Borland C++, PLOSS ("partial loss
of precision") errors are never detected and precision problems simply
ignored.


5.3.1 Differences between Borland C++ 4.0 and earlier versions
------------------------------------------------------------------

Borland C++ uses the function _matherr in the way described above only
from version 4.0 on. Earlier versions employ the function matherr
(without the leading underbar in the function name). In order to be
usable both with the new and the old versions, VectorLib primarily
calls matherr as for the older versions. The include-file <VecLib.h>
provides a macro NEWMATHERR for the redirection of these calls to the
new _matherr(). This macro should appear somewhere in the module
containing the main() or WinMain() procedure, after the header:
    #include <VecLib.h>
    #include ...
    NEWMATHERR
      ......
    main()
    { ... }



5.4 The Treatment of Denormal Numbers
-------------------------------------

"Denormal" are very small numbers between zero and the smallest full-
accuracy number available in the respective data type.  You may
understand the underlying principle from a simplified example:
1.175494E-38 is the smallest "normal" float, with 7-digit accuracy.
What about 1/1024 of this value? This can only be represented as
0.001145E-38, which is accurate to only four digits, since the first
three digits are needed to hold zeros. Thus, denormal numbers provide a
smooth transition between the smallest representable normal numbers and
zero.

In general, they may be treated just as ordinary numbers. In some instances,
however, like taking the inverse, overflow errors may occur. In these cases,
the somewhat academic distinction between SING and OVERFLOW errors is dropped
and a SING error signalled (as if it was a division by exactly 0).

On the other hand, for functions like the logarithms, very small input numbers
may give perfectly reasonable results, although the exact number 0.0 is an
illegal argument, leading to a SING error. Here, the possible loss of
precision is neglected and denormals are considered valid arguments.
(This treatment is quite different from that chosen for the math functions of
Borland C/C++, where denormal arguments lead to SING errors also in these
cases, which seems less appropriate to us.)



5.5 Advanced Error Handling: Writing Messages into a File
---------------------------------------------------------

ANSI C provides the user-definable function perror to print error messages.
However, several compilers, including Borland C++, do not use perror for
this purpose. This means that the way error messages are printed is not
controllable by the programmer. While this is fine in most instances, there
may be situations in which you might, for example, wish the error messages
not to be printed to the screen, but rather into a file, so that you could
check later what has gone wrong. If you use Borland C++ for Windows, an
additional motivation could come from the fact that, for any error, a
message box is displayed and program execution interrupted until you
acknowledge having taken notice of the error.

You might wish to circumvent this. To this end, VectorLib provides the
function  V_setErrorEventFile. This function needs as arguments the desired
name of your event file and a switch named ScreenAndFile which decides if the
error message is printed only into the file, or additionally to the screen
as well.

Note that this redirection of error messages is valid only for errors
occurring in VectorLib routines. If you wish to do so, however, there is a
way to extend the redirection also to the "non-VectorLib" functions:  you
may modify  _matherr and _matherrl such that the statement
    return 0;
(which signals an unresolved error)  is replaced by the sequence
    V_noteError( e->name, e->type ); return 1;
Thereby the task of printing the error message for unresolved errors is
passed to the VectorLib function V_noteError. Keep in mind that it is the
return value of _matherr which decides if an error message is printed by the
default error handler of Borland C/C++. Thus, after the call to V_noteError,
the printing of the default error messages is by-passed by returning "1".
(Also, do not forget that VectorLib uses your _matherr routine to determine
which errors you accept and which not!)

For example, your _matherr function (matherr - without the leading underbar
- for Borland C++ 3.0 and 3.1) might look like the following one:

    #include <math.h>
    int  _matherr( struct exception *e)
    {
        if( (e->type == UNDERFLOW)  (e->type == TLOSS) ) ;    /* ignore */
        else   /* all other errors deserve at least notice */
        {
              V_noteError( e->name, e->type );
              if (e->type == DOMAIN) exit(1); /* really fatal */
        }
        return 1;
    }

(Of course, if you decide to change _matherr, do not forget to change
_matherrl in the same way!).

The default printing of error messages on the screen alone is restored by
V_closeErrorEventFile.

A way to keep track also of those errors which do not lead to messages is
opened by the return values of mathematical VectorLib functions. Any of the
"silent" TLOSS along with the more serious DOMAIN, SING and OVERFLOW errors
will lead to a non-zero return value. You may wish to check for a clean
result after a group of functions, like in the following example:

   unsigned ErrFlag;
   ...
         /*   part Trig1  */
   ErrFlag=0;   /* reset the flag */
   ErrFlag |= VF_sin( Y1, X1, sz );
   ErrFlag |= VF_cos( Y2, X1, sz );
   ErrFlag |= VF_atan2( Z1, Y1, Y2, sz );
   if( ErrFlag ) printf( "Errors occurred in part Trig1 ! ");
   ...

As indicated in the example, it is better to use the   |=  operator instead
of  +=  (since,  in rare cases, all return values might add up to 65536,
which is stored as 0 due to an overflow of the integer variable). Even if
you chose addition of the individual return values, the number of occurred
errors would not be obtainable from the result; in case of an error, any
non-specified non-zero number is returned.



****************************************************************************
*                                                                          *
*******                    6. Trouble-Shooting                       *******
*                                                                          *
****************************************************************************


6.1 General Problems
--------------------

In case of problems, please check first if VectorLib is correctly installed
(see chapter 1.4). If this is the case, carefully check the following points
whose violation would inevitably lead to failure.

*   The choice of the VectorLib library must match your selection of memory
    model, processor, and environment. You are not going to have much fun
    with the library VCL3.LIB under Windows3.x (where you need VCL3W.LIB).

*   You must not use vectors with a size of 0. All functions tacitly assume
    that the vectors have at least one element and do not waste your computer
    time testing for that.

*   You must not use vectors that are only declared, but have no allocated
    memory (see the description of VF_vector). If you did not switch off
    warnings, you may be warned also by the compiler not to do that
    ("possible use of xxx before definition").

*   Constant parameters should not exceed 1.E32 for floats, 1.E150 for
    doubles,  or 1.E2000 for long doubles. Normally, these ranges should
    suffice for any application...

*   16-bit only: Do not forget to write the line
        NEWMATHERR
    after the header into the module containing main(),  WinMain(),  or
    OwlMain(), in order to maintain compatibility both with older and later
    versions of Borland C++  (see chapter 5.3.1).

Although VectorLib has been tested very thoroughly, there is, of course,
always the possibility that a problem might have escaped our attention.
Should you feel you discovered a "bug" in VectorLib, please try to specify
the situation causing the problem as exactly as possible and let the author
know!



6.2 Problems with Windows3.x?
----------------------------

Programming for 16-bit Windows is much more involved than programming for
DOS. While DOS gives the programmer almost complete control over both the
main processor and the coprocessor, Windows demands much of this control for
itself. This introduces problems you should be aware of. They are not at all
specific to VectorLib. However, since they seem not to be very widely known,
here is a collection of some of them. Up to now, these problems have not
been observed with the memory model FLAT used with Win32 (Microsoft's 32-bit
extension of Windows 3.1), Windows NT and Windows95.

*   The background routines controlling intermediate results do not only work
    at the expense of your time, they may also at some point decide to load a
    NULL selector into the segment registers FS and GS. If you happen to use
    these registers (somehow, they were meant by Intel to be used), Windows'
    answer on your next operation will be the familiar "General Protection
    Fault (Error 13)". Therefore, the Windows versions of VectorLib do not
    use FS and GS at all.

*   If a multiplication or division happens to result in a so-called
    "denormal number" (see chapter 5.4), Windows at first accepts this
    result. The next time you use this denormal result, however, Windows
    decides that it had better been zero. Checking for zero by a comparison
    like
          if(x != 0.0)...
    yields the correct answer that x it is not zero, but, after (!) this
    check, Windows makes x exactly zero, if it is loaded onto the number
    stack. This leads to hard-to-find errors. If you inspect VectorLib
    routines with the debugger, you may at some points encounter strange,
    seemingly ineffecient code being used for comparisons. This is a fix for
    the described problem which costs time, but saves you from Windows-
    induced DIVIDE ERROR crashes.

*   Related to the last problem is another feature of Windows: after the
    comparison of two floats or two doubles, one of which is denormal, -NAN
    ("minus not-a-number")  may appear on the number stack. Some time later,
    this leads to a "Floating-point invalid" or a "Stack Overflow" error -
    another means of killing your application. If you encounter -NAN on the
    number stack when debugging your programs (with or without VectorLib
    used), you should find out which comparison(s) caused the problem and add
    the line
           asm  ffree ST(0);
    after this or these comparisons.



6.3 Problems with the 16-bit Linker?
------------------------------------

When working with large programs and libraries, older versions of TLINK
sometimes run into problems. You may get error messages like "Linker stack
overflow", "Out of memory", "Table limit exceeded", "Extended dictionaries
ignored", or "Unresolved external xxx referenced from module yyy".

Try to give the linker as much memory as possible by closing applications,
removing drivers etc. If that does not help, re-arrange your project list.
Curiously enough, that solves the problem sometimes.

In the case of "Unresolved external" linker errors, there is only one way
(if the error is not caused by wrong spelling). First you have to use TLIB
in order to get a listing of the respective library (see the description of
TLIB !). Screening the .LST file thus obtained with a text editor, you find
the module containing the symbol which the linker was unable to locate.
Using again TLIB, you have to extract this module from the library and add
the resulting .OBJ file to your project list.


7. The include-files of VectorLib
---------------------------------

The prototypes for the VectorLib routines are to be found in the include-
files described below. If you are using Borland's ObjectWindows Library
(i.e., if you write true Windows applications without relying on EasyWin),
the OWL include-files have to be included before (!) the VectorLib include-
files.

<VecLib.h> contains the basic definitions of the data types along with the
prototypes of the functions common to all data types (prefix V_) except for
the graphics initialization functions. The trigonometric tables (see chapter
4.6.8) and the few non-vectorized math functions needed internally by
VectorLib  (see chapter 9), are made publically accessible and are declared
in <xmath.h>.

<newcplx.h> is the complex class library CMATH replacing Borland's
<complex.h> for C++ modules.
<cmath.h> and its "children" <cfmath.h>, <cdmath.h> and <cemath.h>
are the CMATH include files for plain-C modules.

<VIstd.h>, <VSIstd.h>, <VLIstd.h>, <VQIstd.h>, <VUstd.h>, <VUSstd.h>,
<VULstd.h>, <VUIstd.h>, <VFstd.h>,  <VDstd.h>,  <VEstd.h>,  <VCFstd.h>,
<VCDstd.h>,  and <VCEstd.h>
contain the prototypes of the functions used for the generation and
initialization of vectors, for index-oriented manipulations, data-type
interconversions, and I/O operations. For the floating-point data types,
they also contain the prototypes of routines for statistics, analysis,
geometrical vector arithmetics, and Fourier-Transform related functions. In
<VFstd.h>, the real-number functions for the data type float (prefix VF_)
are to be found, in <VDstd.h> those for the data type double, and so on.

The algebraic and mathematical functions are declared in the <V..math.h>
header files: <VImath.h>,  <VSImath.h>,  <VLImath.h>, <VQImath.h>,
<VUmath.h>,  <VUSmath.h>, <VULmath.h>,  <VUImath.h>, <VFmath.h>,
<VDmath.h>,  <VEmath.h>,   <VCFmath.h>,   <VCDmath.h>,  and  <VCEmath.h>.

<Vgraph.h> contains the prototypes of the graphics and plotting routines for
all data types.


*****************************************************************************


For detailed information on each single function of VectorLib, see the

S e c o n d  P a r t :  File  FUNCREF.TXT

 8.  Alphabetical Reference

 9.  Non-vectorized Functions

10.  VectorLib Error Messages


*****************************************************************************

Copyright (C) Martin Sander 1996-1998
