OptiVec Logo 


Site Index:

OptiVec home


5. Error Handling

5.1 General Remarks
5.2 Integer Errors
5.3 Floating-Point Errors
5.3.1 C/C++ specific
5.3.2 Pascal/Delphi specific
5.3.3 Error Types (Both C/C++ and Pascal/Delphi)
5.4 The Treatment of Denormal Numbers
5.5 Advanced Error Handling: Writing Messages into a File
5.6 OptiVec Error Messages

5.1 General Remarks

There are two general 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 OptiVec 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 extended-precision versions. They do not have a "safety margin" left as in the single- and double-precision 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 OptiVec 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-2n 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.

Back to VectorLib Table of Contents   OptiVec home 

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 as being performed modulo the respective power of 2 (see chapter 4.4). For those situations in which implicit modulo 2n arithmetics is not appropriate, OptiVec 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 2n arithmetics and interchanges signed and unsigned data types according to their bit pattern. For the 16-bit and 32-bit integer types (but not for 8-bit and 64-bit), there is a second version which also employs modulo 2n arithmetics, but detects the errors. This second variant is denoted by the letter "o" (for "overflow detection") in the prefix: VIo_, VSIo_, VULo_, etc. (for the data-type interconversion functions, the prefix V_ is changed into Vo_). Here, the action to be taken in the case of INTEGER OVERFLOW or INTEGER DOMAIN errors has to be defined by calling V_setIntErrorHandling somewhere before the call to the VIo_ function. V_setIntErrorHandling takes an argument of the type V_ihand (defined in <VecLib.h> and the unit VecLib) with one of three possible values:
ierrNoteprint an error message
ierrAbortprint an error message and exit the program
ierrIgnore ignore the problem. With this last option, the error handling can be switched off intermediately.
Although you may use a call to
V_setIntErrorHandling( ierrIgnore );
to switch the error handling off, it is always better simply to use the "normal" VI_ version rather than the VIo_ version with the error-handling short-cut, as the normal version is always much faster.

C/C++ only:
To choose the overflow-detecting version not only for single function calls, but everywhere, the easiest way is to define symbolic constant V_trapIntError in the program header before(!) <VecLib.h> is included:
#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. */

Back to VectorLib Table of Contents   OptiVec home 

5.3 Floating-Point Errors

5.3.1 C/C++ specific

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 your C++ compiler.
(Borland C++ only: 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. _matherrl is used in the VE_ and VCE_ versions (32-bit Embarcadero / Borland C++ only, as neither Visual C++ nor 64-bit RAD Studio support 80-bit real numbers).

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.

Back to VectorLib Table of Contents   OptiVec home 

5.3.2 Pascal/Delphi specific

The types of errors occurring in mathematical functions are described in detail below. How OptiVec handles each type of error is defined by a call to V_setFPErrorHandling. The possible options are set by the fperrXXX constants described with V_setFPErrorHandling. When calling V_setFPErrorHandling, combine these constants by the OR operator. Note that this influences only the way errors are handled within OptiVec functions. It does not affect the way how the standard Borland Pascal/Delphi functions handle errors.

In addition to the error handling "by element", the return values of the mathematical functions show if all elements have been processed error-free (return value FALSE) or if an error occurred and was handled (return value TRUE).

Back to VectorLib Table of Contents   OptiVec home 

5.3.3 Error Types (Both C/C++ and Pascal/Delphi)

For each VectorLibfunction, the types of errors that are detected and handled are noted in the individual descriptions. All functions derived from ANSI C or Pascal math functions (those whose declarations are to be found in <V?math.h> or the units V?math) 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 FALSE or 0) or if an error occurred and was handled (return value TRUE or different from 0).

In the following description of all floating-point error types, we denote by "HUGE_VAL" the largest number possible in the respective data type. 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.

  • 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. For C/C++, 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 your C/C++ compiler). 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.
    For Pascal/Delphi, we recommend not to change the default setting of V_FPErrorHandlingMode or to include "fperrAbortDOMAIN" in any changes.
    Note: the pseudo-numbers INF and NAN are not allowed as input for any functions of OptiVec. 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.
    C/C++ only: 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 Xi 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 Pi and q are passed as x and y to _matherr).
  • TLOSS ("total loss of precision") errors are detected 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 the OptiVec error handler 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 p. 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 the error handler, 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 the Borland compilers and Visual C++, PLOSS ("partial loss of precision") errors are never detected and precision problems simply ignored.

Back to VectorLib Table of Contents   OptiVec home 

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 most compilers, where denormal arguments lead to SING errors also in these cases, which seems less appropriate to us.)

Back to VectorLib Table of Contents   OptiVec home 

5.5 Advanced Error Handling: Writing Messages into a File

Quite generally, the libraries shipped with compilers do not offer the programmer much control over the way error messages are printed. 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. An additional motivation could come from the fact that, for any error occurring in a Windows program, 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, OptiVec 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 OptiVec routines. If you wish to do so, however, there is a way in C/C++ to extend the redirection also to the "non-OptiVec" 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 OptiVec 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 your compiler. 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 OptiVec uses your _matherr routine to determine which errors you accept and which not!)

Both C/C++ and Pascal/Delphi: The default printing of error messages on the screen alone is restored by V_closeErrorEventFile.

Back to VectorLib Table of Contents   OptiVec home 

5.6 OptiVec Error Messages

Just as with any C/C++ or Pascal program, errors occurring within mathematical functions lead to the appropriate error messages. See paragraph 5.3.3 for details.
Apart from math errors, there are some run-time errors specific to OptiVec routines. These errors lead to the messages noted below. The name of the function where the error occurred is not always exactly the name you wrote in your program. Instead of the prefix VI_, the message will read VLI_ or VSI_, depending on the memory model used. Similarly, instead of VU_, you will find VUL_ or VUS_.
VFs_FFT or VFl_FFT will be substituted for VF_FFT, again depending on the memory model. The reason for this behavior is that many functions share code and even names.


(00) OptiVec/CMATH not installed correctly
(must use INSTALL.EXE !)
Shareware version only: Either you are running a program containing OptiVec functions on a different computer than the one on which you installed OptiVec. The distribution of applications containing OptiVec functions is possible only with the Registered version.
Or you attempted to install OptiVec by unzipping the package by hand, without using INSTALL.EXE. This is not possible, as INSTALL.EXE also starts the clock for the trial period.


(0) Trial period for OptiVec/CMATH has expired!
Shareware version only: Consider ordering the registered version!


(1) Not enough memory.
You are trying to allocate memory, but there is not enough left. This error occurs mostly in connection with "forgotten" vectors that are allocated but never freed. Try these solutions:
* Look out for vectors that might be no longer needed and free them as soon as possible. Be sure that any vectors allocated in subroutines are freed before leaving the subroutine.
* Are you still working with 16-bit models? If you need to work with large amounts of data, the memory model FLAT should be used, working with Win32, WindowsNT, or Windows95/98.
* Store data intermediately on disk, using VF_store, and retrieve them using VF_recall, when needed. This method is slow and should be used only if really unavoidable.


(2) Vector > 64 kB not possible (16-bit).
(2) Vector > 4 GB not possible (32-bit).

* Either you are trying to allocate a vector whose size exceeds the maximum of 4 GB (32-bit) or 64 kB (16-bit except HUGE).
* Or you are in the HUGE model and attempt to process a huge vector in a function where the size is limited to 64 kB even in this model. This might happen, e.g., if the table is too large in one of the interpolation routines. In this case, you must either use the model FLAT or split up your problem into smaller vectors.


(3) Vectors/matrices must not be identical.
In some functions where more than one input vector (or matrix) is used to calculate more than one output vector (or matrix), attention has to be paid, which output data may or may not overwrite which input data. See the specification of the function where the error occurred.


(4) Cannot use requested format (too many entries per line).
This error occurs with the printing functions. The parameter nperline was chosen too large. The function automatically selects the maximum nperline possible and continues execution, but you should nevertheless consider adapting your program.


(6) Not possible with fewer than n elements.
Some functions require a minimum size of n elements of the vector processed.


(7) Not possible with more than n elements.
Some functions are limited to a maximum size of n elements. This is true, for example, for VF_polyinterpol, where only up to 10 table elements may be used for the each interpolation.


(8) Size must be an integer power of 2.
For all functions using - explicitly or implicitly - Fast Fourier Transform methods, the size has to be an integer power of 2. Enlarge or truncate your vector(s) to meet that condition.


(9) Invalid parameter(s).
In some functions, certain combinations of input parameters are illegal. For example, it is not possible to perform a 9-point interpolation on only 5 data points.


(10) Cannot scale symbols by more than a factor of 50.
(Windows only.) The symbols used in VectorLib plotting functions cannot be magnified by more than a factor of 50 (which means already filling the screen with a single symbol). Program execution is continued with a value of 50.0.


(11) Cannot use line thicker than 500 pixels.
(Windows only.) The lines used in VectorLib plotting functions cannot be thicker than 500 pixels (which is already nonsense). Program execution is continued with a value of 500.


(12) Cannot free non-existent vector.
You called V_free or V_nfree for a vector that has no memory allocated. Program execution is continued without freeing anything.

Back to VectorLib Table of Contents   OptiVec home 

6. Trouble-Shooting

In case of problems, please check first if OptiVec is correctly installed. If this is the case, carefully check the following points whose violation would inevitably lead to failure.
  • The choice of the OptiVec library must match your selection of memory model, processor, and environment. With Borland C++, you are not going to have much fun with the libraries designed for Visual C++ and vice versa.
  • 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...
Have a look at our support page for recent known problems. Although OptiVec has been tested thoroughly, there is, of course, always the possibility that a problem might have escaped our attention. Should you feel you discovered a "bug" in OptiVec, please try to specify the situation causing the problem as exactly as possible and let us know at support@optivec.com!

Back to VectorLib Table of Contents   OptiVec home 

7. The Include-Files and Units of OptiVec

All OptiVec C/C++ include-files have the same names as the corresponding Pascal/Delphi units. Naturally, the extension is different: ".H" for the C/C++ include-files, ".DCU" for Delphi units. Below, only the names are listed, without the extension.

C/C++ only: Declare the use of OptiVec functions with #include statements. If you are using MFC (Microsoft Foundation Classes) or the OWL (ObjectWindows Library) with old Borland compilers, the MFC or OWL include-files have to be #included before (!) the OptiVec include-files.

Pascal/Delphi only: Declare the use of OptiVec functions with the uses clause.

Include-file (add suffix .H) or unitContents
VecLibBasic definitions of the data types along with the functions common to all data types (prefix V_) except for the graphics initialization functions.
VFstd, VDstd, VEstdFloating-point "standard operations:" generation and initialization of vectors, index-oriented manipulations, data-type interconversions, statistics, analysis, geometrical vector arithmetics, Fourier-Transform related functions, I/O operations.
VCFstd, VCDstd, VCEstd,
VPFstd, VPDstd, VPEstd
Standard operations for cartesian and polar complex vectors
VIstd, VBIstd, VSIstd, VLIstd, VQIstdStandard operations for signed integer vectors
VUstd, VUBstd, VUSstd, VULstd, VUIstdStandard operations for unsigned integer vectors (VUIstd only for C/C++)
VFmath, VDmath, VEmathAlgebraic, arithmetical and mathematical functions for floating-point vectors
VCFmath, VCDmath, VCEmath,
VPFmath, VPDmath, VPEmath
Arithmetical and mathematical functions for complex vectors
VImath, VBImath, VSImath, VLImath, VQImathArithmetical and mathematical functions for signed integer vectors
VUmath, VUBmath, VUSmath, VULmath, VUImathArithmetical and mathematical functions for unsigned integer vectors (VUImath only for C/C++)
VgraphGraphics functions for all data types
VFNLFIT, VDNLFIT, VENLFITNon-linear fitting functions (Pascal/Delphi only; in C/C++, they are in M?std)
VFMNLFIT, VDMNLFIT, VEMNLFITNon-linear fitting functions for multiple data sets (Pascal/Delphi only; in C/C++, they are in M?std)
MFstd, MDstd, MEstdMatrix operations for real-valued matrices
MCFstd, MCDstd, MCEstdMatrix operations for cartesian complex matrices
MgraphMatrix graphics functions for all data types
MFNLFIT, MDNLFIT, MENLFITNon-linear fitting functions for Z = f(X, Y) data (Pascal/Delphi only; in C/C++, they are in M?std)
MFMNLFIT, MDMNLFIT, MEMNLFITNon-linear fitting functions for multiple Z = f(X, Y) data sets (Pascal/Delphi only; in C/C++, they are in M?std)
NEWCPLXcomplex class library CMATH; C++ only
CMATHcomplex library CMATH for Pascal/Delphi and plain C
CFMATH, CDMATH, CEMATHC/C++ only: type-specific parts of CMATH.
XMATHA few non-vectorized math functions needed internally by other OptiVec functions; they are publically accessible. C/C++: declares also the sine, cosec, and tangent tables for VF_sinrpi2 etc.
sine tables (Pascal/Delphi only; for C/C++, they are in XMATH)
cosecant tables (Pascal/Delphi only; for C/C++, they are in XMATH)
tangent tables (Pascal/Delphi only; for C/C++, they are in XMATH)
VecObjbasic definitions for VecObj, the object-oriented interface for C++
fVecObj, dVecObj, eVecObjVecObj member functions for real-valued vector objects (C++ only)
cfVecObj, cdVecObj, ceVecObj
pfVecObj, pdVecObj, peVecObj
VecObj member functions for complex vector objects (C++ only)
iVecObj, biVecObj, siVecObj, liVecObj, qiVecObjVecObj member functions for signed-integer vector objects (C++ only)
uVecObj, ubVecObj, usVecObj, ulVecObj, uiVecObjVecObj member functions for unsigned-integer vector objects (C++ only)
OptiVecincludes the whole OptiVec package (C++ only)
VecAllincludes all VectorLib and CMATH functions (C or C++ only)
MatAllincludes all MatrixLib functions (C or C++ only)

Back to VectorLib Table of Contents   OptiVec home 

Copyright © 1996-2020 OptiCode - Dr. Martin Sander Software Development

Last modified: 10 January 2018