OptiVec logo 

OptiVec
 
Version 8


for C/C++,   Delphi and Lazarus

OptiCode
Dr. Martin Sander Software Development
Brahmsstr. 6
D-32756 Detmold
Germany
http://www.optivec.com
e-mail: optivec@gmx.de

Part I. A: Handbook

This HANDBOOK describes the basic principles of the OptiVec libraries and gives an overview over VectorLib, the first part of OptiVec. The object-oriented interface, VecObj, is described in chapter 3. The other parts have their own descriptions in separate files, see MATRIX.HTM and CMATH.HTM.
Chapter 1.2 of this Handbook contains the licence terms for the Demo version, Chapter 1.3 for the Registered version.
 
OptiCode? and OptiVec? are trademarks of Dr. Martin Sander Software Dev. Other 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 für das Herunterladen der Demo-Version über das Internet für alle so gering wie möglich zu halten, enthält diese nur die englische Dokumentation. Sie finden die deutsche Beschreibung separat unter http://www.optivec.de/download/OVDOCD.ZIP.

Contents

1. Introduction
1.1 Why Vectorized Programming Pays Off on the PC
 1.1.1 General OptiVec Optimization Strategies
 1.1.2 Multi-Processor Optimization
 1.1.3 CUDA Device Support
 1.1.4 Choosing the right OptiVec Library
1.2 License Terms for the Demo Version
1.3 Registered Versions
 1.3.1 Registered Versions: Ordering
 1.3.2 License Terms for the Registered Versions
1.4 Getting Started
1.5 Declaration of OptiVec Functions 1.6 Sample Programs 2. The Elements of OptiVec Routines
2.1 Synonyms for Some Data Types
2.2 Complex Numbers: The Data Types fComplex, dComplex, eComplex, fPolar, dPolar, and ePolar
2.3 Vectors and Arrays: The Data Types fVector, dVector, eVector, cfVector, pfVector, iVector, uVector, etc.
2.4 Real-Number Functions: The Prefixes VF_,  VD_, and VE_
2.5 Complex-Number Functions: The Prefixes VCF_,  VCD_,  VCE_,  VPF_,  VPD_, and VPE_
2.6 Functions of the Integer Data Types: The Prefixes VI_,  VBI_,  VSI_,  VU_, etc.
2.7 Common Functions of Several Data Types: The Prefix V_
3. C++ only: VecObj, the Object-Oriented Interface for VectorLib
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, Accumulations
4.6.5 Geometrical Vector Arithmetics
4.6.6 Powers
4.6.7 Exponentials and Hyperbolic Functions
4.6.8 Logarithms
4.6.9 Trigonometric Functions
4.7 Analysis
4.8 Signal Processing: Fourier Transforms and Related Topics
4.9 Statistical Functions and Building Blocks
4.10 Data Fitting
4.11 Input and Output
4.12 Graphics
5. Error Handling
5.1 General Remarks
5.2 Integer Errors
5.3 Floating-Point Errors
5.4 The Treatment of Denormal Numbers
5.5 Advanced Error Handling: Writing Messages into a File
5.6 OptiVec Error Messages
6. Trouble-Shooting 7. The Include-Files and Units of OptiVec

P a r t I. B : File FUNCREF.HTM contains:
 
8. Alphabetical Reference of Vector Functions
9. Scalar (non-vectorized) Functions


1. Introduction

OptiVec offers a powerful set of routines for numerically demanding applications, making the philosophy of vectorized programming available for C/C++ and Pascal/Delphi languages. It 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.

In contrast to integrated packages like MatLab or others, OptiVec has the advantage of being incorporated into the modern and versatile languages C/C++ and Pascal/Delphi. Both 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 convenient means of letting the compiler write the loop for you and then compile it to the usual inefficient code. The same is true for most implementations of the popular BLAS (Basic Linear Algebra Subroutine) libraries.
In comparison to these approaches, OptiVec 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!

There is a certain overlap in the range of functions offered by OptiVec and by BLAS, LINPACK, and other libraries and source-code collections. However, the latter must be compiled, and, consequently, their performance is determined mainly by the quality of the compiler chosen. To the best of our knowledge, OptiVec, was, in 1996, the first product on the market offering a comprehensive vectorized-functions library realized in a true Assembler implementation – and has only grown and evolved since.

The wide range of routines and functions covered by OptiVec, the high numerical efficiency and increased ease of programming make this package a powerful programming tool for scientific and data analysis applications, competing with (and often beating) many high-priced integrated systems, but imbedded into your favourite programming language.

This documentation describes the OptiVec implementations for

Please note that only the "outside appearance" and thus the documentation is the same for these different compilers. The libraries themselves are compiler-specific; each library can be used only with one compiler and, in the case of C/C++, with one memory model or one target:
  1. Demo Versions
    The Demo version contains only a selection of libraries:
    1. 64-bit: P8D (General-Purpose debug library, back-compatible to Core2 / AMD64) and
      P9M (automatic multi-threading; up-to-date processors required: Haswell+ / Excavator+).
    2. 32-bit: P4D: General-Purpose debug version, using the FPU for maximum floating-point accuracy, safety and widest processor compatibility range - down to 486DX / Pentium / Athlon.
      This version runs on all 32-bit Windows versions (including the 32-bit mode of 64-bit Windows).
    3. 32-bit: P8M: Multi-Core library for use on AMD64 x2, Core2 Duo or their multi-core successors. In addition to the automatic distribution of the work load over the available processor cores (auto-threading), the speed is also enhanced by employing SSE, SSE2, SSE3 etc. command sets for many floating-point operations. Be prepared, however, to accept a certain loss of accuracy as a consequence of the use of SSE commands. Overflow, singularity, and loss-of-precision errors are treated "silently" by setting the default result as indicated in the documentation of each function.
     
  2. Full Registered Versions
    The libraries come in several versions of processor utilization: These versions are differentiated into sub-versions:

Specifics of the OptiVec versions for the different compilers

Details will be described in Chap. 1.4 in connection with the different libraries. At this point, only a summary is given:

Back to Table of Contents

1.1 Why Vectorized Programming Pays Off on the PC

To process one-dimensional data arrays or "vectors", a programmer would normally write a loop over all vector elements. Similarly, two- or higher-dimensional arrays ("matrices" or "tensors") are usually processed through nested loops over the indices in all dimensions. The alternative to this classic style of programming are vector and matrix functions.
Vector functions act on whole arrays/vectors instead of single scalar arguments. They are the most consequent form of "vectorization", i.e., organisation of program code (by clever compilers or by the programmer himself) in such a way as to optimize vector treatment.

Vectorization has always been the magic formula for supercomputers with their multi-processor parallel architectures. On these architectures, one tries to spread the computational effort equally over the available processors, thus maximizing execution speed. The so-called "divide and conquer" algorithms break down more complicated numerical tasks into small loops over array elements. Sophisticated compilers then find out the most efficient way how to distribute the array elements among the processors. Many supercomputer compilers also come with a large set of pre-defined proprietary vector and matrix functions for many basic tasks. These vectorized functions offer the best way to achieve maximum throughput.

Obviously, the massive parallel processing of, say, a Cray is not possible even on modern PCs with their modest 2, 4 or 8-processor core configurations. Consequently, at first sight, it might seem difficult to apply the principle of vectorized programming to the PC. Actually, however, there are many vector-specific optimizations possible, even for computers with only one CPU. Most of these optimizations are not automatically available to present compilers. Rather, one has to go down to the machine-code level. Hand-optimized, Assembler-written vector functions outperform compiled loops by a factor of two to three, on the average. This means that vectorization, properly done, is indeed worth the effort, also for PC programs.

1.1.1 General OptiVec Optimization Strategies

Here are the most important optimization strategies, employed in OptiVec to boost the performance on any PC (regardless of the number of processor cores):

Preload of constants
Floating-point as well as integer constants, employed in the evaluation of mathematical functions, are loaded into registers outside of the actual loop and stay 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.

Prefetch of chunks of vector elements
Beginning with the Pentium III processor, Intel introduced the very useful feature of explicit memory prefetch. With these commands, it is possible to "tell" the processor to fetch data from memory sufficiently in advance, so that no time is wasted waiting for them when they are actually needed.

Full XMM and FPU stack usage
Where necessary, all eight (64-bit: all sixteen) XMM registers and/or all eight coprocessor registers are employed.

Use of SIMD commands
You might wonder why this strategy is not listed first. The SSE or "Streaming Single-Instruction-Multiple-Data Extensions", introduced since the days of the Pentium III and improved with every new processor generation, provide explicit support for vectorized programming with floating-point data in float / single or double precision. At first sight, therefore, they should revolutionize vector programming. Given the usual relation between processor and data bus speeds, however, many of the simple arithmetic operations are data transfer limited, and the use of SIMD commands does not make the large difference (with respect to well-written FPU code) it could make otherwise. In many cases, the advantage of using an SIMD instruction instead of separate FPU instructions melts down to a 20-30% increase in speed (which is not that bad, anyway!). For more complicated operations, on the other hand, SIMD commands often cannot be employed, either because conditional branches have to be taken for each vector element individually, or because the "extra" accuracy and range, available by traditional FPU commands (with their internal extended accuracy), allows to simplify algorithms so much that the FPU code is still faster. As a consequence, we use SIMD commands only where a real speed gain is possible. Please note, however, that, the SIMD-employing library versions (P8, P9 etc.) generally sacrifice 1-2 digits of accuracy in order to attain the described speed gain. If this is not acceptable for your specific task, please stay with the P4 libraries.

Superscalar scheduling
By careful "pairing" of commands whose results do not depend upon each other, the parallel integer pipes and fadd/fmul units of the processor are used as efficiently as possible.

Loop-unrolling
Where SIMD instructions cannot be used and where optimum pairing of commands cannot be achieved for single elements, vectors are often processed in chunks of two, four, or even more elements. This allows to fully exploit the parallel execution pipes. Moreover, the relative amount of time spent for loop management is significantly reduced. In connection with data-prefetching, described above, the depth of the unrolled loops is most often adapted to the cache line size.

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

Replacement of floating-point by integer commands
For any operations with floating-point numbers that can also be performed using integer commands (like copying, swapping, or comparing to preset values), the faster method is consistently employed.

Strict precision control
C compilers convert a float into a double – Borland Pascal/Delphi even into extended – before passing it to a mathematical 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, but it is simply inefficient on modern PCs. Consequently, no such implicit conversions are present in OptiVec routines. Here, a function of a float is calculated to float (i.e. single) precision, wasting no time for the calculation of more digits than necessary – which would be discarded anyway. There is also a brute-force approach to precision-control: You can call V_setFPAccuracy( 1 ); to actively switch the FPU to single precision, if that is enough for a given application. Thereby, execution can be slightly sped up from Pentium CPUs on. Be, however, prepared to accept even lower-than-single accuracy of your end results, if you elect this option. For further details and precautions, see V_setFPAccuracy.

All-inline coding
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 onto the stack.

Cache-line matching of local variables
The Level−1 cache of modern processors uses 64-byte lines. Many OptiVec functions need double-precision or extended-precision real local variables on the stack (mainly for integer/floating-point conversions or for range checking). 32-bit compilers align the stack on 4-byte boundaries, which means there is a certain chance that the 8 bytes of a double or the 10 bytes of an extended, stored on the stack, will cross a cache-line boundary. This, in turn, would lead to a cache line-break penalty, deteriorating the performance. Consequently, those OptiVec functions where this is an issue, use special procedures to align their local variables on 8-byte (for doubles), 16-byte (for extendeds), or 64-byte boundaries (for XMM and YMM values).

Unprotected and reduced-range functions
OptiVec offers alternative forms of some mathematical functions, where you have the choice between the fully protected variant with error handling and another, unprotected variant without. In the case of the integer power functions, for example, the absence of error checking allows the unprotected versions to be vectorized much more efficiently. Similarly, the sine and cosine functions can be coded more efficiently for arguments that the user can guarantee to lie in the range -2p and +2p. In these special cases, the execution time may be reduced by up to 40%, depending on the hardware environment. This increased speed has always to be balanced against the increased risk, though: If any input element outside the valid range is encountered, the unprotected and reduced-range functions will crash without warning.

1.1.2 Multi-Processor Optimization

Multithread support
Modern multi-core processors allow the operating system to distribute threads among the available processors, scaling the overall performance with the number of available processor cores. For that, any functions running in parallel must be prevented from interfering with each other through read/write operations on global variables. With very few exceptions (namely the plotting functions, which have to use global variables to store the current window and coordinate system settings), all other OptiVec functions are reentrant and may run in parallel.

When designing your multi-thread application, you have two options: functional parallelism and data parallelism.

Functional Parallelism
If different threads are performing different tasks – they are functionally different – one speaks of functional parallelism. As an example, consider one thread handling user input / output, while another one performs background calculations. Even on a single-core CPU, this kind of multi-threading may offer advantages (e.g., the user interface does not block during extensive background calculations, but still takes input). On a multi-core computer, the two (or more) threads can actually run simultaneously on the different processor cores. In general, however, the load balance between the processor cores is far from perfect: often, one processor is running at maximum load, while another one is sitting idle, waiting for input. Still, functional multithreading is the best option whenever your numerical tasks involve vectors and matrices of only small-to-moderate size.

Data Parallelism
In order to improve the load balance between the available processor cores, thereby maximizing throughput, it is possible to employ classical parallel processing: the data to be processed is split up into several chunks, each thread getting one of these chunks. This is aptly called data parallelism. The usefulness of this approach is limited by the overhead involved in the data distribution and in the thread-to-thread communication. Moreover, there are always parts of the code which need to be processed sequentially and cannot be parallelized. Therefore, data parallelism pays off only for larger vectors and matrices. Typical break-even sizes range from about 100 (for the calculation of transcendental functions of complex input values) to several 10,000 elements (as in the simple arithmetic functions). Only when your vectors and matrices are considerably larger than that threshold, the performance is actually improved over a functional-parallelism approach. The boost then quickly approaches (but never exactly reaches) the theoretical limit of a factor equal to the number of processor cores available.

1.1.3 CUDA Device Support

Modern graphics cards are equipped with powerful multiprocessor capacity of up to several hundred processor kernels running in parallel. In recent years, interfaces have been developed, allowing to exploit this processing capacity not only for graphics rendering, but also for general calculations. One of these approaches is the CUDA concept by NVIDIA. All current NVIDIA graphics cards support CUDA. Additionally, dedicated CUDA hardware is being offered by NVIDIA for high-performance computing. With the cudaOptiVec libraries (marked by a "C" in the library name, e.g., OVVC8C.LIB or OVBC64_8C.a), OptiVec offers a simple way to use a CUDA device for vector / matrix calculations without the hassles of actually programming in CUDA. There are a number of points to be considered:

1.1.4 Choosing the right OptiVec Library

Whenever you want your application to run on a wide range of supported platforms, and when your vectors and matrices are only of small-to-moderate size, we recommend to use the general-purpose libraries. For 64-bit, these are OVVC64_8.Lib  (for MS Visual C++),  OVBC64_8.LIB  (C++ Builder),  or the units in OPTIVEC\WIN64\LIB8  (for Delphi). For 32-bit, take OVVC4.LIB  (for MS Visual C++),  VCF4W.LIB  (Embarcadero/Borland C++ compiler series),  or the units in OPTIVEC\LIB4  (for Delphi). These libraries combine good performance with back-compatibility to older hardware, in 32-bit even down to 486DX, Pentium, Athlon. They are all multi-thread safe and support functional parallelism. If you do not need full floating-point accuracy and that amount of back-compatibility, you can get higher performance by switching to the P8 or P9 libraries (marked by the respective number in the in the library name).

For large vectors/matrices on multi-core machines, multi-core optimized libraries actively distribute the work load over the available processor cores for data parallel execution. These libraries are marked by the letter "M", as in  OVVC8M.LIB  (for MS Visual C++, using SSE2),  VCF4M.LIB  (for Embarcadero/Borland C++, full FPU accuracy),  or the units in OPTIVEC\LIB8M  (for Delphi, using SSE3). These libraries are designed for AMD 64 x2,    Intel Core2 Duo, or machines equipped with several discrete processors of the Pentium 4+ level. The CUDA libraries are based on the "M" libraries and are marked by the letter "C", as, e.g., in  OVVC8C.LIB.
The "M" and "C" libraries will still run on single-core machines, but – due to the thread-management overhead – somewhat slower than the general-purpose libraries. Although the "M" libraries are designed with medium to large vectors in mind, the penalty for using them with smaller vectors is almost negligible, as the OptiVec thread-engine automatically executes a function in a single thread, if the vector size is too small for parallel execution to earn back the cost involved in the thread-to-thread communication.
If you use the "M" or "C" libraries, your programme must call V_initMT( nAvailProcCores ) before any of the vector functions.

Back to Table of Contents

1.2 Licence Terms for the Demo Version

The following licence terms apply to the Demo version of OptiVec. For the licence terms of the Registered version, please see paragraph 1.3.
 
This is the Demo version of OptiVec ("SOFTWARE").
It may be used under the following licence terms:
  1. You may test the SOFTWARE free of charge for a period of up to 90 days on one computer.
  2. Applications, created with the Demo version of this SOFTWARE, will run only on the same computer on which this SOFTWARE has been installed. They cannot and may not be distributed to others. After the end of the trial period, they will cease functioning.
  3. If you want to continue using this SOFTWARE after testing, and/or if you wish to distribute programs containing functions of this SOFTWARE, you have to purchase the registered version (see chapter 1.3).
  4. Special conditions apply for the 32-bit P4D and the 64-bit P8D library for GCC and for LLVM CLang: These libraries are Freeware. You can use them free of charge for as long as you wish, both for non-commercial and commercial applications. Applications, created with these libraries, may be distributed free of restrictions to others.
  5. This SOFTWARE is provided on an "as is" basis. Any explicit or implicit warranties for the SOFTWARE are excluded.
  6. 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.
  7. 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.
  8. You may not decompile, disassemble, or otherwise reverse engineer the SOFTWARE into a machine-readable form. You may, however, inspect the functions it contains by means of debuggers like those included in the Borland and Microsoft compilers.
Copyright for the SOFTWARE and its documentation © 1996-2024 OptiCode – Dr. Martin Sander Software Dev.
All rights reserved, including those of translation into foreign languages.

Back to Table of Contents

1.3 Registered Versions

1.3.1 Registered Versions: Ordering

You can either get a license for the OptiVec / CMATH version designed for one specific compiler ("OptiVec / CMATH for xxx"), or you can acquire an OptiVec / CMATH Master License, covering all supported compilers.
In order to make this product affordable also for those who will not themselves make money using it, we offer an educational edition at a strongly reduced rate, in addition to the full commercial edition. The contents of these two editions is identical. The only difference lies in the restrictions of use: The educational edition may not be used for commercial / business / government purposes, but is restricted to private and educational use.

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.

The right to distribute applications employing functions of OptiVec is included in the commercial-version licence. No run-time licence are needed for your customers! Corporate site and world-wide licences are available upon request.

Price List

 
OptiVec for single compilers:
C++ Builder,    Visual C++,   GCC (Win),   LLVM CLang (Win),   Delphi,   Lazarus / FreePascal,    or Linux (GCC / LLVM CLang)
  Prices incl. 19% German VATPrices net
Commercial Edition 
Single license
 5 units
10 units
EUR   199
EUR   595 (119.00 per unit)
EUR   995 ( 99.50 per unit)
EUR   167.23
EUR   500.00 (100.00 per unit)
EUR   836.13 ( 83.61 per unit)
Educational Edition
Single license
 5 units
10 units
EUR    99
EUR   269 ( 53.80 per unit)
EUR   499 ( 49.90 per unit)
EUR    83.19
EUR   226.05 ( 45.21 per unit)
EUR   419.33 ( 41.93 per unit)
 
OptiVec Master License for all supported compilers
  Prices incl. 19% German VATPrices net
Commercial Edition 
Single license
 5 units
10 units
EUR   299
EUR   899 (179.80 per unit)
EUR  1499 ( 149.90 per unit)
EUR   251.26
EUR   755.46 (151.09 per unit)
EUR  1259.66 (125.97 per unit)
Educational Edition
Single license
 5 units
10 units
EUR   149
EUR   445  (89.00 per unit)
EUR   745  (74.50 per unit)
EUR   125.21
EUR   373.95  (74.79 per unit)
EUR   626.05  (62.61 per unit)
 
CMATH separately; for single compilers:
C++ Builder,    Visual C++,   GCC (Win),   LLVM CLang (Win),   Delphi,   Lazarus / FreePascal,    or Linux (GCC / LLVM CLang)
  Prices incl. 19% German VATPrices net
Commercial Edition 
Single license
 5 units
10 units
EUR    59
EUR   175  (35.00 per unit)
EUR   295  (29.50 per unit)
EUR    49.58
EUR   147.06  (29.41 per unit)
EUR   247.90  (24.79 per unit)
Educational Edition
Single license
 5 units
10 units
EUR    29
EUR    85  (17.00 per unit)
EUR   145  (14.50 per unit)
EUR    24.37
EUR    71.43  (14.29 per unit)
EUR   121.85  (12.19 per unit)
 
CMATH separately; master license for all supported compilers
  Prices incl. 19% German VATPrices net
Commercial Edition 
Single license
 5 units
10 units
EUR    89
EUR   265  (53.00 per unit)
EUR   445  (44.50 per unit)
EUR    74.79
EUR   222.69  (44.54 per unit)
EUR   373.95  (37.40 per unit)
Educational Edition
Single license
 5 units
10 units
EUR    49
EUR   145  (29.00 per unit)
EUR   245  (24.50 per unit)
EUR   41.18
EUR   121.85  (24.37 per unit)
EUR   205.88  (20.59 per unit)

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

Please order through www.optivec.de/order/
or send this order form to

OptiCode – Dr. Martin Sander Software Dev.
Brahmsstr. 6
D-32756 Detmold
Germany
optivec@gmx.de

Back to Table of Contents

1.3.2 License Terms for the Registered version

If you got this file with the registered version of OptiVec, these are the license terms valid for you:
 
This is a single copy license for OptiVec ("SOFTWARE"), granted by OptiCode – Dr. Martin Sander Software Development ("OptiCode").

The SOFTWARE in this package is licensed to you as the user. It is not sold. The term "user" means a programmer who links binary code of this SOFTWARE into his own applications. Those people using, in turn, his applications without the need of installing this SOFTWARE themselves, do not need any runtime license for the SOFTWARE. The right to distribute applications containing code of this SOFTWARE is included in the license fee for the commercial version.

Once you have paid the required license fee, you may use the SOFTWARE for as long as you like, provided you do not violate the copyright and if you observe the following rules:

  1. You may use the SOFTWARE on any computer for which it is designed, as long as not more than one person uses it at any time.
  2. You may make backup copies of the SOFTWARE for your personal use. You may only transfer the SOFTWARE to somebody else if you transfer the original and all copies, retaining no copies for yourself. You may not lease or rent the SOFTWARE to others.
  3. You may not decompile, disassemble, or otherwise reverse engineer the SOFTWARE into a machine-readable form. You may, however, inspect the functions contained in this SOFTWARE by means of debuggers like those included in the Borland and Microsoft compilers.
  4. If you payed the reduced licence fee for the "educational version" rather than the full rate for the "commercial version", the use of this SOFTWARE is restricted to private and educational purposes. In this case, you may not use the SOFTWARE for commercial purposes or for government purposes other than education.
    Applications using functions of this SOFTWARE may be freely distributed (i.e. without any run-time licence) only if created with the "commercial edition" and on condition that the functions of this SOFTWARE are permanently linked into a program etc., but do not appear as a library to the user of that application.
  5. 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.
  6. OptiCode's liability is limited by the enclosed Limited Warranty. In no case shall OptiCode's liability exceed the license paid for the right to use the SOFTWARE.

Limited Warranty for the Registered version
  1. OptiCode warrants that the magnetic or optic media on which the SOFTWARE is recorded are free from defects in materials and workmanship under normal use. The SOFTWARE itself will perform substantially in accordance with the specifications set forth in the documentation.
  2. The above express warranties are made for a period of six months from the date the SOFTWARE is delivered to you as the first user.
  3. Any magnetic/optic or printed media from this package proving defective in materials or workmanship will be replaced on an exchange basis.
  4. Great care has been taken to ensure that the SOFTWARE operates in accordance with the specifications as described in the documentation. However, it is not guaranteed that this SOFTWARE will operate completely free of errors or that the documentation is free of errors.
  5. Any implied warranties including any warranties of merchantability or of fitness for a particular purpose are limited to the terms of the above express warranties.
  6. OptiCode shall not in any case be liable for special, incidental, consequential, indirect or other damages arising from any breach of these warranties or of the license conditions, even if he has been notified of the possibility of such damages.

Copyright for the SOFTWARE and its documentation © 1996-2024 OptiCode – Dr. Martin Sander Software Development. All rights reserved.

Back to Table of Contents

1.4 Getting Started

In order to use OptiVec, you need an already installed copy of your C/C++, Delphi, or Lazarus / FreePascal compiler. Install OptiVec by executing INSTALL.EXE. Normally, OptiVec will be installed into a directory named "OPTIVEC". This directory holds the documentation.
You will need to include the OptiVec "lib" and "include" (C/C++) or units (Pascal/Delphi) subdirectories into the search path.
Jump to the description for your specific version:
 OptiVec for C++ Builder (Embarcadero / Borland C++)
OptiVec for Visual C++
OptiVec for GCC
OptiVec for LLVM CLang
OptiVec for Delphi
OptiVec for Lazarus / FreePascal
OptiVec for Linux with GCC or CLang

1.4.1 OptiVec for C++ Builder (Embarcadero / Borland C++)

Assuming your OptiVec directory is C:\OPTIVEC, add
C:\OPTIVEC\LIB to the library search path and
C:\OPTIVEC\INCLUDE to the include-file search path of the IDE (and of the configuration file BCC32.CFG in case you are using the command-line compiler).
You have to include two OptiVec libraries: First the OptiVec base library. Please note the necessary distinction between static and dynamic BCC runtime in 32-bit.
 
PlatformCompilerstatic runtime libraryruntime library as DLL
Win64xbcc64x (modern), from RAD Studio 12.1.1 (2024) onovbcbase64cs.libovbcbase64cd.lib
Win64bcc64 (classic), from RAD Studio 12.x (2023) onovbcbase64.aovbcbase64.a
 bcc64, all versions until RAD Studio 11.xovbcx64.aovbcx64.a
Win32bcc32 (classic), RAD Studio 12+ovbcbase32s.libovbcbase32d.lib
 bcc32 (classic), all versions until RAD Studio 11.xvcfs.libvcfd.lib
 bcc32c (CLang-enhanced), RAD Studio 12+ovbcbase32cs.libovbcbase32cd.lib
 bcc32c (CLang-enhanced),all versions until RAD Studio 11.xovbc10_11base32cs.libovbc10_11base32cd.lib

Second, select the required processor-specific library from the following table and add it to your project. Here, there is no difference between the classic and the CLang-enhanced compiler.
 
PlatformCompilerProcessorGeneral-purposeDebugMulti-ProcessorMP+CUDA
Win64xbcc64xP9: Haswell+ / Excavator+OVVC64x_9.lib ---- OVBC64x_9M.libOVBC64x_9C.lib
 bcc64xP8: AMD64xxx, Core2xxxOVBC64x_8.libOVBC64x_8D.libOVBC64x_8M.libOVBC64x_8C.lib
Win64bcc64P9: Haswell+ / Excavator+OVVC64_9.a ---- OVBC64_9M.aOVBC64_9C.a
 bcc64P8: AMD64xxx, Core2xxxOVBC64_8.aOVBC64_8D.aOVBC64_8M.aOVBC64_8C.a
Win32bcc32 (classic)P8: AMD64xxx, Core2xxxVCF8W.LIB ---- VCF8M.LIBVCF8C.LIB
  P4: Max compatibility, full FPU accuracyVCF4W.LIBVCF4D.LIBVCF4M.LIB ----
 bcc32c (CLang)
from C++ Builder 10.1 Berlin on
P8: AMD64xxx, Core2xxxovbc32c_8.lib ---- ovbc32c_8m.libovbc32c_8c.lib
  P4: Max compatibility, full FPU accuracyovbc32c_4.libovbc32c_4d.libovbc32c_4m.lib ----
 bcc32c (CLang)
up until C++ Builder 10 Seattle
P8: AMD64xxx, Core2xxxVCF8W.LIB ---- VCF8M.LIBVCF8C.LIB
  P4: Max compatibility, full FPU accuracyVCF4W.LIBVCF4D.LIBVCF4M.LIB ----
 
The libraries for multi-processor systems run on workstations with discrete processors, as well as on multi-core processors like AMD64x2, Core2 Duo and so on.

In order to profit from the CUDA-enhanced OptiVec library, do the following things:

  1. In addition to the OptiVec base library selected above, include the base import library OVBCCU32.lib (32-bit), OVBCCU64.lib (Win64x), OVBCCU64.a (Win64, up-to-date CUDA devices), or OVBCCULEG64.lib (Win64x) / OVBCCULEG64.a (Win64, legacy CUDA devices with comp.cap. 3.5, 5.0, 6.0).
  2. Make sure the corresponding DLL, OVBCCU32.DLL, OVBCCU64.DLL, or OVBCCULEG64.DLL is either in the same directory as the executable you are about to create, or in another directory contained in the Windows environment variable PATH.
  3. Include the processor-specific OptiVec library, ending with the letter "C", e.g. VCF8C.LIB or OVBC64_8C.lib.

In previous versions, there were certain restrictions concerning the use of CMATH with the 32-bit CLang-enhanced Borland Compiler bcc32c.exe. All of them have now been lifted.

Continue with chap. 1.5 Declaration of OptiVec functions in C/C++

1.4.2 OptiVec for Visual C++ (Microsoft Visual Studio)

Assuming your OptiVec directory is C:\OPTIVEC, add
C:\OPTIVEC\LIB to the library search path and
C:\OPTIVEC\INCLUDE to the include-file search path.
You have to include two OptiVec libraries. The first one ("base library") contains the interface between OptiVec and the VC++ runtime library; it has to be matched with the specific version of the VC++ runtime library you chose for your project. The second one is independent from the configuration and runtime library; you have to choose it according to the desired CPU support.
First choose the project configuration and runtime library. The latter is set at Project / (Configuration) Settings / C/C++ / Code Generation / Runtime Library. Under Project / (Configuration) Settings / Linker / Input, add the matching OptiVec library to your project, according to the following table.
 
PlatformVisual Studio versionRuntime Debug DLLDebug StaticRelease DLLRelease Static
Win64VS 2022OVVC17x64MDD.LIBOVVCx64MTD.LIBOVVC17x64MDR.LIBOVVCx64MTR.LIB
Win64VS 2019OVVC16x64MDD.LIBOVVCx64MTD.LIBOVVC16x64MDR.LIBOVVCx64MTR.LIB
 VS 2017OVVC15x64MDD.LIBOVVCx64MTD.LIBOVVC15x64MDR.LIBOVVCx64MTR.LIB
 VS 2015OVVC14x64MDD.LIBOVVCx64MTD.LIBOVVC14x64MDR.LIBOVVCx64MTR.LIB
 VS 2013OVVC12x64MDD.LIBOVVC8_12x64MTD.LIBOVVC12x64MDR.LIBOVVC8_12x64MTR.LIB
 VS 2012OVVC11x64MDD.LIBOVVC8_12x64MTD.LIBOVVC11x64MDR.LIBOVVC8_12x64MTR.LIB
 VS 2010OVVC8x64MDR.LIB*OVVC8_12x64MTD.LIBOVVC8x64MDR.LIBOVVC8_12x64MTR.LIB*
 VS 2008OVVC8x64MDR.LIB*OVVC8_12x64MTD.LIBOVVC8x64MDR.LIB*OVVC8_12x64MTR.LIB
 VS 2005OVVC8x64MDD.LIBOVVC8_12x64MTD.LIBOVVC8x64MDR.LIBOVVC8_12x64MTR.LIB
Win32VS 2022OVVC17MDD.LIBOVVCMTD.LIBOVVC17MDR.LIBOVVCMTR.LIB
 VS 2019OVVC16MDD.LIBOVVCMTD.LIBOVVC16MDR.LIBOVVCMTR.LIB
 VS 2017OVVC15MDD.LIBOVVCMTD.LIBOVVC15MDR.LIBOVVCMTR.LIB
 VS 2015OVVC14MDD.LIBOVVCMTD.LIBOVVC14MDR.LIBOVVCMTR.LIB
 VS 2013OVVC12MDD.LIBOVVC8_12MTD.LIBOVVC12MDR.LIBOVVC8_12MTR.LIB
 VS 2012OVVC11MDD.LIBOVVC8_12MTD.LIBOVVC11MDR.LIBOVVC8_12MTR.LIB
 VS 2010OVVC10MDD.LIBOVVC8_12MTD.LIBOVVC10MDR.LIBOVVC8_12MTR.LIB
 VS 2008OVVC9MDD.LIBOVVC8_12MTD.LIBOVVC9MDR.LIBOVVC8_12MTR.LIB
 VS 2005OVVC8MDD.LIBOVVC8_12MTD.LIBOVVC8MDR.LIBOVVC8_12MTR.LIB
 
*For the outdated VS releases 2008 and 2010, the base libraries for 64-bit DebugDLL and ReleaseDLL are not available. As a work-around, you can use the release-version of the VS 2005 library, OVVC8x64MDR.LIB. Additionally, you need the VS 2005 Redistributable. You find it at www.microsoft.com/download. Enter "vcredist_x64" into the search field to get a list of available redistributables and choose the VS 2005 one. You will get linker warnings about a library conflict, which you can ignore in this specific case.

Please note that there is a certain inconsistency in the description of the configurations in Visual Studio: The default configurations "Debug" and "Release" actually use the runtime library and MFC as DLL. Therefore, you have to use the OptiVec base libraries OVVC??MDD.lib and OVVC??MDR.lib with these configurations. There is a problem with using these configurations, however: you always need the RTL and MFC DLL's for the specific compiler version installed on your computer. For many applications, it is therefore recommended to change Project / Properties / Configuration Properties / C/C++ / Code Generation / Runtime Library into "Multi-Thread Debug (/MTd)" or "Multi-Thread Release (MT)", respectively, in order to get rid of the DLL redistributables. This is done in the "DebugStatic" configuration in the demo files coming with OptiVec.

After that, please add the second, processor-specific OptiVec library according to the following table:
ProcessorGeneral-purpose libraryDebug libraryMulti-ProcessorMP + CUDA64-bit General64-bit Debug64-bit Multi-Proc.64-bit MP + CUDA
P9: Haswell+ / Excavator+ ---- ---- ---- ---- OVVC64_9.LIB ---- OVVC64_9M.LIBOVVC64_9C.LIB
P8: AMD64xxx, Core2xxxOVVC8.LIB ---- OVVC8M.LIBOVVC8C.LIBOVVC64_8.LIBOVVC64_8D.LIBOVVC64_8M.LIBOVVC64_8C.LIB
P4: Full FPU accuracy, 486DX/PentiumOVVC4.LIBOVVC4D.LIBOVVC4M.LIB ---- ---- ---- ---- ----
 
The libraries for multi-processor systems run on workstations with discrete processors, as well as on multi-core processors like AMD64x2, Core2 Duo and so on.
In order to allow OptiVec to be used in applications both with and without MFC, it calls the Windows API only directly, not via MFC. However, if you use MFC (either as a static library or as a DLL), Visual C++ does not automatically link the import library, user32.lib. You have to explicitly do this yourself: The line, Project / (Configuration) Settings / Linker / Input / Object and Library Modules must contain user32.lib. Otherwise you would get the linker error "error LNK2001: Unresolved external symbol __imp__MessageBoxA@??".
 

In order to profit from the CUDA-enhanced OptiVec library, do the following things:

  1. In addition to the OptiVec base library selected above, include the base import library OVVCCU32.lib (32-bit), OVVCCU64.lib (64-bit, up-to-date CUDA devices), or OVVCCULEG64.lib (64-bit, legacy CUDA devices with comp.cap. 3.5, 5.0, 6.0).
  2. Make sure the corresponding DLL, OVVCCU32.DLL, OVVCCU64.DLL, or OVVCCULEG64.DLL is either in the same directory as the executable you are about to create, or in another directory contained in the Windows environment variable PATH.
  3. Include the processor-specific OptiVec library, ending with the letter "C", e.g. OVVC8C.LIB or OVVC64_8C.lib.

Continue with chap. 1.5 Declaration of OptiVec functions in C/C++

1.4.3 OptiVec for GCC (GNU Compiler Collection) on Windows

Assuming your OptiVec directory is C:\OPTIVEC, you need to compile with the option -I C:\OPTIVEC\INCLUDE.

You have to include two OptiVec libraries. The first one ("base library") contains the interface between OptiVec and the GCC runtime libraries; it has to be matched with the specific configuration of GCC. The second one is independent from the configuration and runtime library; you have to choose it according to the desired CPU support.
First choose the base library from the following table:
 
PlatformGCC thread modelGCC exception modelMatching OptiVec base library
Win64Windows threadsSEHovgcbase64ws.lib
 Windows threadsSetjmp/Longjmpovgcbase64wj.lib
 Posix threadsSEHovgcbase64ps.lib
 Posix threadsSetjmp/Longjmpovgcbase64pj.lib
Win32Windows threadsDwarfovgcbase32wd.lib
 Windows threadsSetjmp/Longjmpovgcbase32wj.lib
 Posix threadsDwarfovgcbase32pd.lib
 Posix threadsSetjmp/Longjmpovgcbase32pj.lib

After that, choose the second, processor-specific OptiVec library according to the following table:
Processor32-bit General-purposeDebugMulti-ProcessorMP + CUDA64-bit General64-bit Debug64-bit Multi-Proc.64-bit MP + CUDA
P9: Haswell+ / Excavator+ ---- ---- ---- ---- ovgc64_9.lib ---- ovgc64_9m.libovgc64_9c.lib
P8: AMD64xxx, Core2xxxovgc32_8.lib ---- ovgc32_8m.libovgc32_8c.libovgc64_8.libovgc64_8d.libovgc64_8m.LIBovgc64_8c.lib
P4: Full FPU accuracy, 486DX/Pentiumovgc32_4.libovgc32_4d.libovgc32_4m.lib ---- ---- ---- ---- ----
 
The libraries for multi-processor systems run on workstations with discrete processors, as well as on multi-core processors like AMD64x2, Core2 Duo and so on.

In order to profit from the CUDA-enhanced OptiVec library, do the following things:

  1. In addition to the OptiVec base library selected above, link with ovgccu32.dll (32-bit), ovgccu64.dll (64-bit, up-to-date CUDA devices), or ovgcculeg64.dll (64-bit, legacy CUDA devices with comp.cap. 3.5, 5.0, 6.0). In contrast to other compilers, GCC can directly link with DLL's, creating its import library "on the fly"; so you do not need to provide a separate import library.
  2. Make sure these DLL's are either in the same directory as the executable you are about to create, or in another directory contained in the Windows environment variable PATH.
  3. Include the processor-specific OptiVec library, ending with the letter "C", e.g. ovgc32_8c.lib or ovgc64_8c.lib.

One very important point to observe when working with GCC is that the linker does not resolve inter-dependencies between included libraries. As the base library and the processor-specific library of OptiVec do have interdependencies, this means that you will have to include them pair-wise at least twice. In each pair, the processor-specific library should come first and the base library second. If you get linker errors about missing OptiVec functions, just include the same pair of libraries once more. For an example, see the makefile for the OptiVec demo programs.

GCC is the only of the "big" compilers to support 80-bit real numbers (long doubles, extended) in 64-bit. This is a very valuable feature, as the extra accuracy and range can make life much simpler on many occasions. OptiVec also supports this data type with the VE_, VCE_, VPE_, ME_, and MCE_ functions.

For the GCC-Linux version of OptiVec for GCC, see below.

Continue with chap. 1.5 Declaration of OptiVec functions in C/C++

1.4.4 OptiVec for LLVM CLang on Windows

Assuming your OptiVec directory is C:\OPTIVEC, you need to compile with the option -I C:\OPTIVEC\INCLUDE.

You have to include two OptiVec libraries. The first one ("base library") contains the interface between OptiVec and the CLang runtime libraries. (Actually, CLang heavily relies on the Visual C++ runtime libraries and is almost compatible with Visual C++. This "almost" compatibility, however, is not perfect, to the point that OptiVec has to come with an individual CLang version.) This base library is ovclbase64.lib for 64-bit and ovclbase32.lib for 32-bit.

The second library is specific to the desired CPU support:
 
Processor32-bit General-purposeDebugMulti-ProcessorMP + CUDA64-bit General64-bit Debug64-bit Multi-Proc.64-bit MP + CUDA
P9: Haswell+ / Excavator+ ---- ---- ---- ---- ovcl64_9.lib ---- ovcl64_9m.libovcl64_9c.lib
P8: AMD64xxx, Core2xxxovcl32_8.lib ---- ovcl32_8m.libovcl32_8c.libovcl64_8.libovcl64_8d.libovcl64_8m.LIBovcl64_8c.lib
P4: Full FPU accuracy, 486DX/Pentiumovcl32_4.libovcl32_4d.libovcl32_4m.lib ---- ---- ---- ---- ----
 
The libraries for multi-processor systems run on workstations with discrete processors, as well as on multi-core processors like AMD64x2, Core2 Duo and so on.

In order to profit from the CUDA-enhanced OptiVec library, do the following things:

  1. In addition to the OptiVec base library selected above, link with ovvccu32.lib (32-bit), ovvccu64.lib (64-bit, up-to-date CUDA devices), or ovvcculeg64.lib (64-bit, legacy CUDA devices down to comp.cap. 3.5). Note that this is no typo: Here, the libraries of cudaOptiVec for Visual C++ are used also for CLang.
  2. Make sure the corresponding DLL's are either in the same directory as the executable you are about to create, or in another directory contained in the Windows environment variable PATH.
  3. Include the processor-specific OptiVec library, ending with the letter "C", e.g. ovcl32_8c.lib or ovcl64_8c.lib.

For the Linux-CLang version of OptiVec, see below.

Continue with chap. 1.5 Declaration of OptiVec functions in C/C++

1.4.5 OptiVec for Delphi

The choice between the various OptiVec libraries is made through the selection of the unit search path. The 64-bit units are in the directories OPTIVEC\Win64\LIB8,  OPTIVEC\Win64\LIB9M etc. The 32-bit units (.DCU files) are in OPTIVEC\LIB4D,   OPTIVEC\LIB8M, etc.
 
When switching from the Demo version to the Registered version, simply install the registered version over the Demo version (and answer "Yes" when asked by INSTALL.EXE, if you want to overwrite the existing files).
You have the following choices:
Processor32-bit General-purposeDebugAutothreading (Multi-Processor)MP + CUDA64-bit General64-bit Debug64-bit Multi-Proc.64-bit MP+CUDA64-bit MP+legacy CUDA
P9: Haswell+ / Excavator+ ---- ---- ---- ---- Win64\LIB9 ---- Win64\LIB9MWin64\LIB9C ----
P8: AMD64xxx, Core2xxxLIB8 ---- LIB8MLIB8CWin64\LIB8Win64\LIB8DWin64\LIB8MWin64\LIB8CWin64\LIB8Cleg
P4: FPU accuracy, 486DX/PentiumLIB4LIB4DLIB4M ---- ---- ---- ---- ---- ----
 
In order to profit from the CUDA-enhanced OptiVec library, make sure OVDCU32.DLL, OVDCU64.DLL (up-to-date CUDA devices), or OVDCULEG64.DLL (legacy CUDA devices down to comp.cap. 3.5) is either in the same directory as the executable you are about to create, or in another directory contained in the Windows environment variable PATH.

Continue with chap. 1.5.2 Declaration of OptiVec functions in Pascal / Delphi

1.4.6 OptiVec for Lazarus / FreePascal

The choice between the various OptiVec libraries is made through the selection of the "Other Units" search path. The units (.PPU files) and object files (*.o) are in the directories OPTIVEC\LIB8,   OPTIVEC\LIB9M, etc.
The Demo version comes with two sets of units, one in the directory LIB8, the other in LIB9M.
In the registered version, you have the following choices:
ProcessorGeneral-purposeDebugAutothreading (Multi-Processor)MP + CUDAMP + legacy CUDA
P9: Haswell+ / Excavator+LIB9 --- LIB9MLIB9C ---
P8: AMD64xxx, Core2xxxLIB8LIB8DLIB8MLIB8CLIB8Cleg
 
In order to profit from the CUDA-enhanced OptiVec library, make sure OVDCU64.DLL (for up-to-date CUDA devices) or OVDCULEG64.DLL (for legacy CUDA devices down to comp.cap. 3.5) is either in the same directory as the executable you are about to create, or in another directory contained in the Windows environment variable PATH.

Continue with chap. 1.5.2 Declaration of OptiVec functions in Pascal / Delphi

1.4.7 OptiVec for Linux with GCC or CLang

You have to include two OptiVec libraries. The first one ("base library") contains the interface between OptiVec and the glibc runtime library. The second one is independent from the configuration and runtime library; you have to choose it according to the desired CPU support.
First choose the base library:
 
PlatformThreadingMatching OptiVec base library
Linux 64Single-threadovlxcbase64s.a
 Multi-threadovlxcbase64m.a

After that, choose the second, processor-specific OptiVec library according to the following table:
ProcessorGeneralDebugMulti-Proc. auto-threading
P9: Haswell+ / Excavator+ovlxc64_9.a ---- ovlxc64_9m.a
P8: AMD64xxx, Core2xxxovlxc64_8.aovlxc64_8d.aovlxc64_8m.a
 
The libraries for multi-processor systems run on workstations with discrete processors, as well as on multi-core processors like AMD64x2, Core2 Duo and so on. They can only be used together with the base library ovlxcbase64m.a and need to be linked with the linker option -lpthread.

One very important point to observe when working with GCC and CLang on Linux is that the linker does not resolve inter-dependencies between included libraries. As the base library and the processor-specific library of OptiVec do have interdependencies, this means that you will have to include them pair-wise at least twice. In each pair, the processor-specific library should come first and the base library second. If you get linker errors about missing OptiVec functions, just include the same pair of libraries once more. For an example, see the makefile for the OptiVec demo programs.

1.5 Declaration of OptiVec functions

1.5.1 Declare the use of OptiVec functions in C/C++

Use #include directives to include the header files described in chapter 7.
To get the whole OptiVec library at once, along with its object-oriented interface, declare
#include <OptiVec.h>
To get only all vector functions (without the object-oriented interface),
#include <VecAll.h>
To add all data-fitting and matrix functions to that,
#include <MatAll.h>.
If you are writing MFC or (very old) Borland C++ ObjectWindows applications, any OptiVec header files should be included after the MFC or OWL header files.

Continue with chap. 1.6 Sample programs

1.5.2 Declare the use of OptiVec functions in Pascal / Delphi

Declare the use of OptiVec units as usual with the "uses" statement. The OptiVec units are grouped according to the data type. See chapter 7. In Delphi, OptiVec units should always be used together with the WinProcs unit, as some data types are borrowed from it. Similarly, with Lazarus, you should always use LCLType together with the OptiVec units.

1.6 Sample programs

Have a look into the sample programs:

After these preparations, all OptiVec functions are available for your programs.
Should you wish to remove OptiVec from your computer, please run UNINSTAL.EXE or simply delete the directory OPTIVEC with its subdirectories.

Back to Table of Contents


2. Elements of OptiVec Routines

2.1 Synonyms for Some Data Types

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

a) C/C++ only:

The data type ui (short for "unsigned index") is used for the indexing of vectors and is defined as "unsigned int".

The 64-bit integer data type (__int64 in BC++ Builder and MS Visual C++, Int64 in Delphi) is called quad (for "quadword integer") in OptiVec.
In 32-bit, the type quad is always signed. Functions for unsigned 64-bit integers are available only in the 64-bit versions of OptiVec.

The data type extended, which is familiar to Pascal/Delphi programmers, is defined as a synonym for "long double" in OptiVec for C/C++. As all 64-bit compilers (Visual C++ even not for 32-bit) do not support 80-bit reals, we define "extended" as "double" in the OptiVec versions for these compilers.
The reason for the choice of the name "extended" is that all OptiVec routines shall have identical names in C/C++ and Pascal/Delphi 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. In the future, high-precision 128-bit real numbers (__fp128 / __float128) would find their place in this series as "G" for "great" and half floats (__fp16) as "H".

b) Pascal/Delphi only:

The data type Float, which is familiar to C/C++ programmers, is defined as a synonym for Single. We prefer to have the letters defining the real-number data types in alphabetical proximity: "D" for Double, "E" for Extended, and "F" for Float. As noted above, 128-bit real numbers (__fp128 / __float128) may find their place in this series as "G" for "great" and Half floats (__fp16) as "H".

For historical reasons (dating back to the development of Turbo Pascal), the various integer data types have a somewhat confusing nomenclature in Delphi. In order to make the derived function prefixes compatible with the C/C++ versions of OptiVec, we define a number of synonyms, as described in the following table:
typeDelphi namesynonymderived prefix
8 bit signedShortIntByteIntVBI_
8 bit unsignedByteUByteVUB_
16 bit signed SmallInt VSI_
16 bit unsigned WordUSmallVUS_
32 bit signed LongInt VLI_
32 bit unsigned  ULongVUL_
64 bit signed Int64QuadIntVQI_
64 bit unsigned (x64 version only!)UInt64UQuadVUQ_
16/32 bit signedInteger VI_
16/32 bit unsignedCardinalUIntVU_

To have a Boolean data type available which is of the same size as Integer, we define the type IntBool. It is equivalent to WordBool in Pascal, but LongBool in Delphi. You will see the IntBool type as the return value of many mathematical VectorLib functions.

Back to Table of Contents

2.2 Complex Numbers:
The Data Types fComplex, dComplex, eComplex, fPolar, dPolar, and ePolar

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.
From early versions on, Borland C++ has also offered 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 Standard C++ library, included from Borland C++ 5 and Visual C++ 6 on, offers the classes complex<float>, complex<double>, and complex<long double>, equipped with basic functionality and the same range of mathematical functions as offered by the class complex.
Later versions of Delphi offer a unit Complex which treats complex number as variant types – with all the inefficiencies associated with such an implementation.
Functions in polar coordinates are not available in any of these approaches.

Most compilers and available libraries implement complex 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 this end, the complex math library CMATH was created and is included in OptiVec. CMATH is described in greater detail in the file CMATH.HTM. If you use any of the non-vectorized functions contained in CMATH with C/C++, 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> for C/C++:
typedef struct { float Re, Im; } fComplex;
typedef struct { double Re, Im; } dComplex;
typedef struct { extended Re, Im; } eComplex;
typedef struct { float Mag, Arg; } fPolar;
typedef struct { double Mag, Arg; } dPolar;
typedef struct { extended Mag, Arg; } ePolar;

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

The corresponding definitions for Pascal/Delphi are contained in the unit VecLib:
type fComplex = record Re, Im: Float; end;
type dComplex = record Re, Im: Double; end;
type eComplex = record Re, Im: Extended; end;
type fPolar = record Mag, Arg: Float; end;
type dPolar = record Mag, Arg: Double; end;
type ePolar = record Mag, Arg: Extended; end;

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 constituent parts separately to the desired value, e.g.,
z.Re = 3.0; z.Im = 5.7;
p.Mag = 4.0; p.Arg = 0.7;

(of course, the assignment operator is := in Pascal/Delphi).
Alternatively, the same initialization can be accomplished by the functions fcplx or fpolr:
C/C++:
z = fcplx( 3.0, 5.7 );
p = fpolr( 4.0, 0.7 );

Pascal/Delphi:
fcplx( z, 3.0, 5.7 );
fpolr( p, 3.0, 5.7 );

For double-precision complex numbers, use dcplx and dpolr, for extended-precision complex numbers, use ecplx and epolr.
Pointers to arrays or vectors of complex numbers are declared using the data types cfVector, cdVector, and ceVector (for cartesian complex) and pfVector, pdVector, and peVector (for polar complex) described below.

Back to Table of Contents

2.3 Vectors and Arrays:
The Data Types fVector, dVector, eVector,
cfVector, cdVector, ceVector, pfVector, pdVector, peVector,
iVector, biVector, siVector, liVector, qiVector,
uVector, ubVector, usVector, ulVector, uqVector, 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> or the unit VecLib. 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:
 
C/C++
typedeffloat *fVector
typedefdouble *dVector
typedefextended *eVector
typedeffComplex *cfVector
typedefdComplex *cdVector
typedefeComplex *ceVector
typedeffPolar *pfVector
typedefdPolar *pdVector
typedefePolar *peVector
typedefint *iVector
typedefbyte *biVector
typedefshort *siVector
typedeflong *liVector
typedefquad *qiVector
typedefunsigned *uVector
typedefunsigned byte *ubVector
typedefunsigned short *usVector
typedefunsigned long *ulVector
typedefuquad *uqVector
typedefui *uiVector
  Pascal/Delphi
typefVector= ^Float;
typedVector= ^Double;
typeeVector= ^Extended;
typecfVector= ^fComplex;
typecdVector= ^dComplex;
typeceVector= ^eComplex;
typepfVector= ^fPolar;
typepdVector= ^dPolar;
typepeVector= ^ePolar
typeiVector= ^Integer;
typebiVector= ^ByteInt;
typesiVector= ^SmallInt;
typeliVector= ^LongInt;
typeqiVector= ^QuadInt;
typeuVector= ^UInt;
typeubVector= ^UByte;
typeusVector= ^USmall;
typeulVector= ^ULong;
typeuqVector= ^UQuad;

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".
 
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.
 
Delphi also offers dynamically-allocated arrays, which may also be used as arguments for OptiVec functions. The following table compares the pointer-based vectors of VectorLib with the array types of Pascal/Delphi:
 
 OptiVec vectorsPascal/Delphi static/dynamic arrays
alignment of first elementon 32-byte boundary for optimum cache-line matching2 or 4-byte boundary (may cause line-break penalty for double, QuadInt)
alignment of following elementspacked (i.e., no dummy bytes between elements, even for 10- and 20-bit typesarrays must be declared as "packed" for Delphi to be compatible with OptiVec
index range checkingDebug libraries: automatic; Release libraries: noneautomatic with built-in size information
dynamic allocationfunction VF_vectorVF_vector0procedure SetLength
initialization with 0optional by calling VF_vector0always
de-allocationfunction V_freeV_freeAllprocedure Finalize
reading single elementsfunction VF_element:
a := VF_element(X,5);
typecast into array also possible:
a := fArray(X)[5];
index in brackets:
a := X[5];
setting single elementsfunction VF_setElement:
VF_setElement(X,5, a);
Delphi only: typecast into array also possible:
fArray(X)[5] := a;
index in brackets:
X[5] := a;
getting the address of a single elementfunction VF_Pelement 
passing to OptiVec functiondirectly:
VF_equ1( X, sz );
address-of operator:
VF_equ1( @X, sz );
passing sub-vector to OptiVec functionfunction VF_Pelement:
VF_equC( VF_Pelement(X,10), sz−10, 3.7);
address-of operator:
VF_equC( @X[10], sz−10, 3.7 );
 
Summarizing the properties of OptiVec vectors and of Pascal/Delphi arrays, the latter are somewhat more convenient and, due to the index range checking, safer, whereas the pointer-based OptiVec vectors are processed faster (due to the better alignment and to the absence of checking routines).

Back to Table of Contents

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

OptiVec supports the usual three floating-point data types: 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 (Pascal: Single), 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. Except for a very few cases, 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).

For the description of the functions in the Alphabetical Reference, 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.

Back to Table of Contents

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

Any prefix with its second letter being "C" denotes a function of cartesian complex numbers. If the second letter is "P", the function is for complex numbers in polar coordinates. 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"), respectively. Likewise, the VPF_,  VPD_, and VPE_ functions work on vector elements of the types fPolar, dPolar, and ePolar, resp.

Return values of the complex data types are not possible in Pascal/Delphi. Therefore, the syntax of those functions returning a complex number is different in C/C++ and Pascal/Delphi.

In contrast to the carelessness with which complex mathematical functions are often treated (see above), the complex functions of OptiVec are designed in such a way 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. See CMATH.HTM for details.

Back to Table of Contents

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

The nomenclature for the signed integer data types is designed in a similar way as for the floating-point data types:
prefix VBI_: data type char (or byte) / ByteInt,
prefix VSI_: data type short int / SmallInt,
prefix VI_: data type int / Integer,
prefix VLI_: data type long int / LongInt (32-bit for Windows, 64-bit for Linux),
prefix VQI_: data type quad / QuadInt.

For the unsigned integer data types, we have:
prefix VUB_: data type unsigned char (unsigned byte) / UByte,
prefix VUS_: data type unsigned short / USmall,
prefix VU_: data type unsigned / UInt,
prefix VUL_: data type unsigned long / ULong (32-bit for Windows, 64-bit for Linux),
prefix VUQ_: data type uquad / UQuad (only for Win64 and Linux),
prefix VUI_: data type ui.

Don't be afraid of so many data types. It is one of the advantages of modern computer languages 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_, and VU_ 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.

Back to Table of Contents

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> or the units VecLib and Vgraph, respectively. The data-type interconversion functions are declared in the include-files or units belonging to the destination type (i.e. the type into which the numbers are converted).

Back to Table of Contents


3. VecObj, theObject-Oriented Interface for VectorLib

VecObj, the object-oriented C++ interface to OptiVec vector functions was written by Brian Dale, Case Western Reserve University. MatObj, the extension for matrices, is now included as well.
Among the advantages VecObj offers are the following: There are a few draw-backs, though, which you should be aware of: VecObj is contained in the include-files <VecObj.h>, <fVecObj.h>, <dVecObj.h> etc., with one include-file for each of the data-types supported in OptiVec.
To get the whole interface (for all data types at once),
#include <OptiVec.h>.
For access to any of the vector graphics functions, always include <OptiVec.h>.

MS Visual C++ and Embarcadero / Borland C++ Builder (but not previous Borland C++ versions): Programmers should put the directive
"using namespace OptiVec;"
either in the body of any function that usestVecObj, or in the global declaration part of the program. Placing the directive in the function body is safer, avoiding potential namespace conflicts in other functions.
The vector objects are defined as classes vector<T>, encapsulating the vector address (pointer) and size.
For easier use, these classes got alias names fVecObj, dVecObj, and so on, with the data-type signalled by the first one or two letters of the class name, in the same way as the vector types described above.

All functions defined in VectorLib for a specific vector data-type are contained as member functions in the respective tVecObj class.
The constructors are available in four forms:
vector(); // no memory allocated, size set to 0
vector( ui size ); // vector of size elements allocated
vector( ui size, T fill ); // as before, but initialized with value "fill"
vector( vector<T> init ); // creates a copy of the vector "init"

For all vector classes, the arithmetic operators
+    -    *    /    +=    -=    *=    /=
are defined, with the exception of the polar-complex vector classes, where only multiplications and divisions, but no additions or subtractions are supported. These operators are the only cases in which you can directly assign the result of a calculation to a vector object, like
fVecObj Z = X + Y; or
fVecObj Z = X * 3.5;
Note, however, that the C++ class syntax rules do not allow a very efficient implementation of these operators. The arithmetic member functions are much faster. If speed is an issue, use
fVecObj Z.addV( X, Y ); or
fVecObj Z.mulC( X, 3.5 );
instead of the operator syntax.
The operator * refers to element-wise multiplication, not to the scalar product of two vectors.

All other arithmetic and math functions can only be called as member functions of the respective output vector as, for example, Y.exp(X). Although it would certainly be more logical to have these functions defined in such a way that you could write "Y = exp(X)" instead, the member-function syntax was chosen for efficiency considerations: The only way to implement the second variant is to store the result of the exponential function of X first in a temporary vector, which is then copied into Y, thus considerably increasing the work-load and memory demands.

While most VecObj functions are member functions of the output vector, there exists a number of functions which do not have an output vector. In these cases, the functions are member functions of an input vector.
Example: s = X.mean();.

If you ever need to process a VecObj vector in a "classic" plain-C VectorLib function (for example, to process only some part of it), you may use the member functions
getSize() to retrieve its size,
getVector() for the pointer (of data type tVector, where "t" stands for the usual type prefix), and
Pelement( n ) for a pointer to the to the n'th element.

The syntax of all VecObj functions is described in FUNCREF.HTM together with the basic VectorLib functions for which tVecObj serves as a wrapper.

Back to Table of Contents


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.

The following functions manage dynamically allocated vectors: 
VF_vectormemory allocation for one vector
VF_vector0memory allocation and initialization of all elements with 0
V_freefree one vector
V_nfree free n vectors (only for C, not for Pascal)
V_freeAllfree all existing vectors
 
You should always take proper care to de-allocate the memory of vectors which are no longer needed. 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/C++ and Pascal/Delphi. 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 OptiVec. Moreover, this makes your programs more easily portable.

Performance tips:

The following functions are used to initialize or re-initialize vectors that have already been created: 
VF_equ0set all elements of a vector equal to 0
VCF_Reequ0set all real parts equal to 0, leaving the imaginary parts unchanged
VCF_Imequ0set all imaginary parts equal to 0, leaving the real parts unchanged
VF_equ1set all elements equal to 1
VF_equm1set all elements equal to −1
VF_equCset all elements equal to a constant C
VF_equVmake one vector a copy of another
VFx_equV"expanded" version of the equality operation: Yi = a * Xi + b
VF_ramp"ramp": Xi = a * i + b.
VUI_ramp"index ramp": Xi = i  (VUI_ and VU_ versions only)
VF_randomLChigh-quality random numbers
VF_randomsimplified form of VF_randomLC for high-quality random numbers
VF_noiseLCwhite noise
VF_noisesimplified form of VF_noiseLC fo white noise
VF_comb"comb": equals a constant C at equidistant points, elsewhere 0
 

The following functions are used to access and modify single vector elements: 
VF_Pelementreturns a pointer to the vector element specified by its index
VF_elementreturns a specific vector element
VF_getElementcopies a specific vector element into a variable
VF_setElementsets a vector element to a new value
VF_accElementX[i] += c; adds a value to one vector element
VF_decElementX[i] -= c; subtracts a value from one vector element
 
The following functions generate windows for use in spectral analysis: 
VF_HannHann window
VF_ParzenParzen window
VF_WelchWelch window
 
Complex vectors may be initialized by these functions: 
VF_ReImtoCmerge two vectors, Re and Im, into one cartesian complex vector
VF_RetoCoverwrite the real part of a cartesian complex vector
VF_ImtoCoverwrite the imaginary part of a cartesian complex vector
VF_PolartoCconstruct a cartesian complex vector from polar coordinates, entered as separate vectors Mag and Arg
VF_MagArgtoPmerge two vectors, Mag and Arg into one polar complex vector
VF_MagArgtoPrincipalmerge two vectors, Mag and Arg into one polar complex vector, reducing the Arg range to the principal value, -p < Arg ≤ +p
VF_MagtoPoverwrite the Mag part of a polar complex vector
VF_ArgtoPoverwrite the Arg part of a polar complex vector
VF_ReImtoPconstruct a polar complex vector from cartesian coordinates, entered as separate vectors Re and Im

Back to Table of Contents

4.2 Index-oriented Manipulations

VF_revreverse the element ordering
VCF_revconjcomplex conjugate and reverse element ordering
VF_reflectset the upper half of a vector equal to the reversed lower half
VF_rotaterotate the ordering of the elements
VF_rotate_bufefficient rotation, employing user-specified buffer memory
VF_insertinsert one element into a vector
VF_deletedelete one element from a vector
VF_sortfast sorting of the elements (ascending or descending order)
VF_sortindsorting of an index array associated with a vector
VF_subvectorextract a subvector from a (normally larger) vector, using a constant sampling interval.
VF_indpickfills a vector with elements "picked" from another vector according to their indices.
VF_indputdistribute 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_subvector_equC Xi*samp = C,   i=0,...subsize−1
VF_subvector_addC Xi*samp += C,   i=0,...subsize−1
VF_subvector_subC Xi*samp -= C,   i=0,...subsize−1
VF_subvector_subrC Xi*samp = C - Xi*samp,   i=0,...subsize−1
VF_subvector_mulC Xi*samp *= C,   i=0,...subsize−1
VF_subvector_divC Xi*samp /= C,   i=0,...subsize−1
VF_subvector_divrC Xi*samp = C / Xi*samp,   i=0,...subsize−1
VF_subvector_equV Yi*samp = Yi,   i=0,...subsize−1
VF_subvector_addV Xi*samp += Yi,   i=0,...subsize−1
VF_subvector_subV Xi*samp -= Yi,   i=0,...subsize−1
VF_subvector_subrV Xi*samp = Yi - Xi*samp,   i=0,...subsize−1
VF_subvector_mulV Xi*samp *= Yi,   i=0,...subsize−1
VF_subvector_divV Xi*samp /= Yi,   i=0,...subsize−1
VF_subvector_divrV Xi*samp = Yi / Xi*samp,   i=0,...subsize−1
 
Searching tables for specific values is accomplished by:
VF_searchC search for the element of a vector that is closest to a pre-set value C (closest, closest larger-or-equal, or closest smaller-or-equal value, depending on a parameter "mode")
VF_searchVthe same, but for a whole array of pre-set values
 
Interpolations are performed by: 
VF_polyinterpolpolynomial interpolation
VF_ratinterpolrational interpolation
VF_natCubSplineInterpolnatural cubic spline interpolation
VF_splineinterpolgeneral cubic spline interpolation
 

Back to Table of Contents

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. Only a few examples are given; the rest should be obvious: 
V_FtoDfloat to double
V_CDtoCFcomplex<double> to complex<float> (with overflow protection)
V_PFtoPEpolar<float> to polar<extended>
VF_PtoCpolar<float> to complex<float>
V_ItoLIint to long int
V_ULtoUSunsigned long to unsigned short
V_ItoUsigned int to unsigned int. Interconversions between signed and unsigned types can only be performed on the same level of accuracy. Functions like "V_UStoLI" do not exist.
V_ItoFint to float
 
The conversion of floating-point numbers into integers is performed by the following functions, differing in the way a possible fractional part is treated: 
VF_roundtoIround to the closest integer
VF_choptoIround by neglecting ("chopping off") the fractional part
VF_trunctoIthe same as VF_choptoI
VF_ceiltoIround to the next greater-or-equal integer
VF_floortoIround to the next smaller-or-equal integer
 
These operations are treated as mathematical functions and are further described in chapter 4.6.1.

Back to Table of Contents

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 2n, 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 2n had been added to (or subtracted from) the "correct" result as necessary to reach the legal range.
For example, in the data type short / SmallInt, 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 / SmallInt is a 16-bit type, so n = 16, and 2n = 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.

Back to Table of Contents

4.5 Basic Functions of Complex Vectors

The following functions are available for the basic treatment of cartesian complex vectors: 
VF_ReImtoCform a cartesian complex vector out of its real and imaginary parts
VF_RetoCoverwrite the real part
VF_ImtoCoverwrite the imaginary part
VF_CtoReImextract the real and imaginary parts
VF_CtoReextract the real part
VF_CtoImextract the imaginary part
VF_PolartoCform a cartesian complex vector out of polar coordinates, entered as separate vectors Mag and Arg
VF_CtoPolartransform cartesian complex into polar coordinates, returned in the separate vectors Mag and Arg
VF_CtoAbsabsolute value (magnitude of the pointer in the complex plane)
VF_CtoArgargument (angle of the pointer in the complex plane)
VF_CtoNormnorm (here defined as the square of the absolute value)
VCF_normtoCnorm, stored as a cartesian complex vector (with all imaginary parts equal to 0)
 
The corresponding functions for polar coordinates are:
VF_MagArgtoPmerge two vectors, Mag and Arg into one polar complex vector
VF_MagArgtoPrincipalmerge two vectors, Mag and Arg into one polar complex vector, reducing the Arg range to the principal value, -p < Arg ≤ +p
VF_MagtoPoverwrite the Mag part of a polar complex vector
VF_ArgtoPoverwrite the Arg part of a polar complex vector
VF_PtoMagArgextract the Mag and Arg parts
VF_PtoMagextract the Mag part
VF_PtoArgextract the Arg part
VF_PtoNormnorm (here defined as the square of the magnitude)
VF_ReImtoPconstruct a polar complex vector from cartesian coordinates, entered as separate vectors Re and Im
VF_PtoReImtransform a polar complex vector into two real vectors, representing the corresponding cartesian coordinates Re and Im
VF_PtoRecalculate the real part of the polar complex input numbers
VF_PtoImcalculate the imaginary part of the polar complex input numbers
VPF_principalcalculate the principal value. You might recall that each complex number has an infinite number of representations in polar coordinates, with the angles differing by an integer multiple of 2 p. The representation with -p < Arg ≤ +p is called the principal value.
 

Back to Table of Contents

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 scalar ANSI C or Pascal functions or derived from them. In C/C++, errors are handled by _matherr and _matherrl. In Pascal/Delphi, OptiVec allows the user to control error handling by means of the function V_setFPErrorHandling.

In addition to this error handling "by element", the return values of the VectorLib math functions show if all elements have been processed successfully. In C/C++, the return value is of the data-type int, in Pascal/Delphi, it is IntBool. (We do not yet use the newly introduced data type bool for this return value in C/C++, in order to make VectorLib compatible also with older versions of C compilers.) If a math function worked error-free, the return value is FALSE (0), otherwise it is TRUE (any non-zero number).

Back to Table of Contents

4.6.1 Rounding

Some of the functions converting floating-point into integer vectors have already been noted above. The result of these rounding operations may either be left in the original floating-point format, or it may be converted into one of the integer types. The following functions store the result in the original floating-point format: 
VF_roundround to the closest integer
VF_chopround by neglecting ("chopping off") the fractional part
VF_truncthe same as VF_chop
VF_ceilround to the next greater-or-equal integer
VF_floorround to the next smaller-or-equal integer
 
The following functions store the result as integers (type int / Integer): 
VF_roundtoIround to the closest integer
VF_choptoIround by neglecting ("chopping off") the fractional part
VF_trunctoIthe same as VF_choptoI
VF_ceiltoIround to the next greater-or-equal integer
VF_floortoIround to the next smaller-or-equal integer
 
The target type may also be any of the other integer data types. A few examples should suffice: 
VF_choptoSIneglect the fractional part and store as short int / SmallInt
VF_ceiltoLIround up and store as long int / LongInt
VF_floortoQIround downwards and store as quadruple integer, quad / QuadInt
VF_roundtoUround and store as unsigned / UInt
VF_ceiltoUSround up and store as unsigned short / USmall
VD_choptoULneglect the fractional part and store as unsigned long / ULong

Back to Table of Contents

4.6.2 Comparisons

Many numerical tasks rely on counting or selecting vector elements according to certain conditions which are formulated as comparisons.
Storing the result of the respective comparison for each element in a mask vector (which may subsequently used to mask out non-conforming vector elements in applications like time series analysis) is done by the VF_cmp_... series.
 
VF_cmp_eq0  /  _eqC  /  _eqVXi =  0  /  C  /  Yi ?   ("equal")
VF_cmp_ne0  /  _neC  /  _neVXi ≠ 0  /  C  /  Yi ?   ("not equal")
VF_cmp_gt0  /  _gtC  /  _gtVXi > 0  /  C  /  Yi ?   ("greater than")
VF_cmp_ge0  /  _geC  /  _geVXi ≥ 0  /  C  /  Yi ?   ("greater than or equal")
VF_cmp_lt0  /  _ltC  /  _ltVXi < 0  /  C  /  Yi ?   ("less than")
VF_cmp_le0  /  _leC  /  _leVXi ≤ 0  /  C  /  Yi ?   ("less than or equal")
VF_cmp_stVXi ≈  Yi ?   ("similar to")
VF_cmp_dtVXi ≉ Yi ?   ("dissimilar to")

As a second possibility, the indices of conforming elements can be stored in an index vector as is done by the VF_cmp_...ind series. Some examples:
 
VF_cmp_neCindIndices of all elements Xi != C
VD_cmp_lt0indIndices of all elements Xi < 0
VE_cmp_geVindIndices of all elements Xi ≥ Yi

Testing if elements fall into a certain range is done by the functions with the postfixes "inclrange0C", "inclrangeCC", "exclrange0C" and "exclrangeCC":
 
VF_cmp_inclrange0C TRUE for 0 ≤ x ≤ C (C positive),
0 ≥ x ≥ C (C negative)
VF_cmp_exclrange0C TRUE for 0 < x < C (C positive),
0 > x > C (C negative)
VF_cmp_inclrangeCC TRUE for CLo ≤ x ≤ CHi
VF_cmp_exclrangeCC TRUE for CLo < x < CHi
VF_cmp_inclrange0Cind Indices of all elements 0 ≤ Xi ≤ C  (C positive),
  0 ≥ Xi > C  (C negative)
VF_cmp_exclrange0Cind Indices of all elements 0 < Xi < C  (C positive),
  0 > Xi > C  (C negative)
VF_cmp_inclrangeCCind Indices of all elements CLo ≤ Xi ≤ CHi
VF_cmp_exclrangeCCind Indices of all elements CLo < Xi < CHi

Counting elements fulfilling a comparison condition is performed by the VF_cnt_... series of functions. Some examples:
 
VF_cnt_eq0count the number of elements equal to 0 (accepting −0 as valid)
VD_cnt_gtCcount the number of elements greater than a constant C
VE_cnt_leVcount the number of elements less than or equal to the corresponding elements of another vector
VLI_cnt_inclrange0Ccount the number of elements xi falling into the range 0 ≤ xi ≤ C or, if C is negative, 0 ≥ xi ≥ C
  

Additionally, the signum function can be performed with the three possible answers +1 for "greater than", 0 for "equal to" or −1 for "less than". For input vectors of the unsigned integer data types, the output vectors are of the corresponding signed integer types.
VF_cmp0signum function: compare to 0: yi = +1, if xi > 0; yi = 0, if xi = 0; yi = −1, if xi < 0.
VU_cmpCcompare to a constant C: yi = +1, if xi > C; yi = 0, if xi = C; yi = −1, if xi < C.
VE_cmpVcompare corresponding vector elements: zi = +1, if xi > yi; zi = 0, if xi = yi; zi = −1, if xi < yi
 
If you want to know only if one or more given values can be found at all in a table (but need neither the exact number nor position of occurrences), use one of the following functions: 
VF_iselementC returns TRUE, if C is an element of a vector
VF_iselementV checks for each element of a vector if it is contained in a table

Back to Table of Contents 

4.6.3 Direct Bit-Manipulation

For the integer data types, a number of bit-wise operations is available, which can be used, e.g., for fast multiplication and divisions by integer powers of 2. 
VI_shlshift the bits to the left
VI_shrshift the bits to the right
VI_orapply a bit mask in an OR operation
VI_xorapply a bit mask in an XOR operation
VI_notinvert all bits

Back to Table of Contents

4.6.4 Basic Arithmetics, Accumulations

As before, 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_negYi = - Xi
VF_absYi = | Xi |
VCF_conjYi.Re = Xi.Re; Yi.Im = −(Xi.Re)
VF_invYi = 1.0 / Xi
 
VF_equCXi = C
VF_addCYi = Xi + C
VF_subCYi = Xi - C
VF_subrCYi = C - Xi
VF_mulCYi = Xi * C
VF_divCYi = Xi / C
VF_divrCYi = C / Xi
VF_modCYi = Xi mod C
VF_equVYi = Xi
VF_addVZi = Xi + Yi
VF_subVZi = Xi − Yi
VF_subrVZi = Yi − Xi
VF_mulVZi = Xi * Yi
VF_divVZi = Xi  /  Yi
VF_divrVZi = Yi  /  Xi
VF_modVZi = Xi mod Yi
VF_add2VZi = Xi + Y1i + Y2i
VF_sub2VZi = Xi - Y1i - Y2i
 
Besides these basic operations, several frequently-used combinations of addition and division have been included, not to forget the Pythagoras formula: 
VF_reldiffCYi = (Xi − C)  /  |C|
VF_reldevCYi = |Xi − C|  /  |C|
VF_hypCYi = Xi  /  (Xi + C)
VF_redCYi = (Xi * C)  /  (Xi + C)
VF_visCYi = (Xi − C)  /  (Xi + C)
VF_hypotCYi = sqrt( Xi² + C² )
VF_reldiffVZi = (Xi − Yi)  /  max(|Xi|, |Yi|)
VF_reldevVZi = |Xi − Yi|  /  max(|Xi|, |Yi|)
VF_hypVZi = Xi  /  (Xi + Yi)
VF_redVZi = (Xi * Yi)  /  (Xi + Yi)
VF_visVZi = (Xi − Yi)  /  (Xi + Yi)
VF_hypotVZi = sqrt( Xi² + Yi²)

The 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
VFx_divrV Zi = Yi / (a * Xi + b)
 
The simple algebraic functions exist also in yet another special form, with the result being scaled by some arbitrary factor. This scaled form gets 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)
 
Other simple operations include: 
VF_maxCset Yi equal to Xi or C, whichever is greater
VF_minCchoose the smaller of Xi and C
VF_maxVset Zi equal to Xi or Yi, whichever is greater
VF_minVset Zi equal to Xi or Yi, whichever is smaller
VF_limitlimit the range of values
VF_flush0set all values to zero which are below a preset threshold
VF_flushInvset all values to zero which are below a preset threshold and take the inverse of all other values
VF_absHugereplace negative poles by positive ones
VF_intfracsplit into integer and fractional parts
VF_mantexpsplit into mantissa and exponent
 
While, in general, all OptiVec functions are for input and output vectors of the same type, the arithmetic functions exist also for mixed-type operations between the floating-point and the integer types. The result is always stored in the floating-point type. Examples are:
 
VF_addVIfVector Z = fVector X + iVector Y
VD_mulVULdVector Z = dVector X * ulVector Y
VE_divrVBIeVector Z = biVector Y / eVector X

Similarly, there exists a family of functions for the accumulation of data in either the same type or in higher-precision data types. Some examples are: 
VF_accVfVector Y += fVector X
VD_accVFdVector Y += fVector X
VF_accVIfVector Y += iVector X
VQI_accVLIqiVector Y += liVector X
 
Additionally, within the floating-point data-types, you can accumulate two vectors at once:  
VF_acc2VfVector Y += fVector X1 + fVector X2
VD_acc2VFdVector Y += fVector X1 + fVector X2

Again only within the floating-point data-types, you can also accumulate squares and products:
VF_accV2fVector Y += fVector X2
VD_accVF2dVector Y += fVector X2
VCF_accVmulVconjcfVector Y += cfVector X * cfVector Y*

Back to Table of Contents 

4.6.5 Geometrical Vector Arithmetics

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 scalar product of two vectors
VF_xprod cross-product (or vector product) of two vectors
VF_Euclid Euclidean norm

If, on the other hand, two real input vectors X and Y, or one complex input vector XY, define the coordinates of several points in a planar coordinate system, there is a function to rotate these coordinates:
VF_rotateCoordinates counter-clockwise rotation of the input coordinates specified by the vectors X and Y; the result is returned in the vectors Xrot and Yrot.
VCF_rotateCoordinates counter-clockwise rotation of the input coordinates specified by the cartesian complex vector XY; the result is returned in the vector XYrot.

Back to Table of Contents 

4.6.6 Powers

The following functions raise arbitrary numbers to specified powers. While the "normal versions" perform full error handling, the extra-fast "unprotected versions" can be employed in situations where you are absolutely sure that all input elements yield valid results. Due to the much more efficient vectorization permitted by the absence of error checks, the unprotected functions are several times as fast as the normal, protected versions. Be, however, aware of the price you have to pay for this increase in speed: in case of an overflow error, the program will crash without any warning.
 
normal versionunprotected versionoperation
VF_squareVFu_squaresquare
VF_cubicVFu_cubiccubic
VF_quarticVFu_quarticquartic (fourth power)
VF_rsquareVFu_rsquarereciprocal square
VF_rcubicVFu_rcubicreciprocal cubic
VF_rquarticVFu_rquarticreciprocal quartic (fourth power)
VF_sqrtVFu_sqrt square-root (which corresponds to a power of 0.5)
VF_rsqrt
VFu_rsqrt reciprocal square-root (which corresponds to a power of −0.5)
VF_inv
VFu_inv reciprocal (power of −1)
VF_ipowVFu_ipowarbitrary integer powers
VF_pown.a.fractional powers
VF_powexpn.a.fractional powers, multiplied by exponential function: xrexp(x)
VF_polyVFu_polypolynomial
VF_polyOddVFu_polyOddpolynomial consisting of odd terms only
VF_polyEvenVFu_polyEvenpolynomial consisting of even terms only
VF_ratioVFu_ratioratio of two polynomials, p/q
VF_ratioOddEvenVFu_ratioOddEvenratio of two polynomials, p/q, where p consists of odd terms only, and q consists of even terms only (like in the rational approximation of the tangent function)
VF_ratioEvenOddVFu_ratioEvenOddratio of two polynomials, p/q, where p consists of even terms only, and q consists of odd terms only (like in the rational approximation of the cotangent function)
 
The following group of functions is used to raise specified numbers to arbitrary powers: 
VF_pow10 fractional powers of 10
VF_ipow10 integer powers of 10 (stored as floating-point numbers)
VF_pow2 fractional powers of 2
VF_ipow2 integer powers of 2 (stored as floating-point numbers)
VF_exp exponential function
VF_exp10 exponential function to the basis 10 (identical to VF_pow10)
VF_exp2 exponential function to the basis 2 (identical to VF_pow2)
VF_expArbBase exponential function of an arbitrary base
 
All of these functions exist also in the expanded "VFx_" form, like
VFx_square: Yi = (a * Xi + b)² 
The expanded form of the unprotected functions has the prefix VFux_.

The complex-number equivalents are available as well, both for cartesian and polar coordinates. Additionally, two special cases are covered:
 
VCF_powReExpo real, fractional powers of complex numbers
VCF_exptoP takes a cartesian input vector, returning its exponential function in polar coordinates.

Back to Table of Contents 

4.6.7 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_exp exponential function
VF_expc complementary exponential function Yi = 1 - exp[Xi]
VF_expmx2 exponential function of the negative square of the argument,
Yi = exp( −Xi² ). This is a bell-shaped function.
VF_Gauss Gaussian distribution function
VF_erf Error function (Integral over the Gaussian distribution)
VF_erfc complementary error function, 1 - erf( Xi )
VF_powexpfractional powers, multiplied by exponential function, Xirexp(Xi)
 
The vectorized hyperbolic functions are available as: 
VF_sinh hyperbolic sine
VF_cosh hyperbolic cosine
VF_tanh hyperbolic tangent
VF_coth hyperbolic cotangent
VF_sech hyperbolic secant
VF_cosech hyperbolic cosecant
VF_sech2 square of the hyperbolic secant

Back to Table of Contents 

4.6.8 Logarithms

VF_log10 decadic logarithm (to the basis 10)
VF_log natural logarithm (to the basis e)
VF_ln synonym for VF_log
VF_log2 binary logarithm (to the basis 2)
 
Again, the cartesian-complex equivalents exist as well. The polar-complex versions, however, are special in that their output is always in cartesian coordinates:
VPF_log10toC decadic logarithm (to the basis 10)
VPF_logtoC natural logarithm (to the basis e)
VPF_lntoC synonym for VPF_logtoC
VPF_log2toC binary logarithm (to the basis 2)

As a special form of the decadic logarithm, the Optical Density is made available by a family of functions of which some examples are contained in the following table: 
VF_ODOD = log10( X0/X ) for fVector as input and as output
VF_ODwDarkOD = log10( (X0−X0Dark) / (X−XDark) ) for fVector as input and as output
VUS_ODtoFOD, calculated in float precision for usVector input
VUL_ODtoDOD, calculated in double precision for ulVector input
VQI_ODtoEwDarkOD with dark-current correction, calculated in extended precision for qiVector input

Back to Table of Contents 

4.6.9 Trigonometric Functions

Some of the basic trigonometric functions are available in two variants. The first variant follows the usual rules of error handling for math functions, whereas the second is for situations where you know beforehand that all input arguments will be in the range -2p ≤ Xi ≤ +2p. If you choose to employ these extra-fast reduced-range functions, you really have to be absolutely sure about your input vectors, as these functions will crash without warning in the case of any input number outside the range specified above. The reduced-range functions are available only for the sine and cosine, as all other trigonometric functions need error checking and handling anyway, even in this range.
 
VF_sinsine
VFr_sinextra-fast "reduced-range" sine function for -2p ≤ Xi ≤ +2p
VF_coscosine
VFr_coscosine for -2p ≤ Xi ≤ +2p
VF_sincossine and cosine at once
VFr_sincossine and cosine for -2p ≤ Xi ≤ +2p
VF_tantangent
VF_cotcotangent
VF_secsecant
VF_coseccosecant
 
The following functions yield the squares of the trigonometric functions in a more efficient way than by first calculating the basic functions and squaring afterwards: 
VF_sin2sine²
VFr_sin2sine² for -2p ≤ Xi ≤ +2p
VF_cos2cosine²
VFr_cos2cosine² for -2p ≤ Xi ≤ +2p
VF_sincos2sine² and cosine² at once
VFr_sincos2sine² and cosine² for -2p ≤ Xi ≤ +2p
VF_tan2tangent²
VF_cot2cotangent²
VF_sec2secant²
VF_cosec2cosecant²
 
A very efficient way to calculate the trigonometric functions for arguments representable as rational multiples of p (PI) is supplied by the trigonometric functions with the suffix "rpi" (meaning "rational multiple of p"). Here, r = p / q, where q is constant and p is given by the input vector elements: 
VF_sinrpisine of p/q * p
VF_cosrpicosine of p/q * p
VF_sincosrpisine and cosine of p/q * p at once
VF_tanrpitangent of p/q * p
VF_cotrpicotangent of p/q * p
VF_secrpisecant of p/q * p
VF_cosecrpicosecant of p/q * p
 
Even more efficient versions use tables to obtain frequently-used values; these versions are denoted by the suffixes "rpi2" (multiples of p divided by an integer power of 2) and "rpi3" (multiples of p over an integer multiple of 3). Examples are: 
VF_sinrpi2 sine of p / 2n * p
VF_tanrpi3 tangent of p / (3*n) * p
 
Two more special trigonometric functions are: 
VF_sinc sinc function, Yi = sin( Xi ) / Xi
VF_Kepler Kepler function, calculating the time-dependent angular position of a planet or comet
 
Vectorized inverse trigonometric functions are available as 
VF_asinarc sin
VF_acosarc cos
VF_atanarc tan
VF_atan2 arc tan of ratios, Zi = atan( Yi / Xi )

Back to Table of Contents 

4.7 Analysis

There is a number of functions probing the analytical properties of data arrays:
 
VF_derivV derivative of a Y-array with respect to an X-array
VF_derivC the same for constant intervals between the X-values
VF_integralV value of the integral of a Y-array over an X-array
VF_runintegralV point-by-point ("running") integral
VF_integralC integral over an equally spaced X-axis
VF_runintegralC point-by-point integral over an equally spaced X-axis
VF_ismonoton test if an array is monotonously rising or falling
VF_iselementC test, if a given value occurs within a vector
VF_searchC search an ordered table for the entry whose value comes closest to a preset value C
VF_localmaxima detect local maxima (points whose right and left neighbours are smaller)
VF_localminima detect local minima (points whose right and left neighbours are larger)
VF_max detect global maximum
VF_min detect global minimum
VF_minmax detect global minimum and maximum
VF_maxind global maximum and its index
VF_minind global minimum and its index
VF_absmax global maximum absolute value
VF_absmin global minimum absolute value
VF_absminmax detect global minimum and maximum absolute values
VF_minpos smallest positive value within a vector
VF_absmaxind global maximum absolute value and its index
VF_absminind global minimum absolute value and its index
VF_maxexp global maximum exponent
VF_minexp global minimum exponent
VF_runmax "running" maximum
VF_runmin "running" minimum

The complex equivalents of the last group of functions are:
 
VCF_maxReIm maximum real and imaginary parts separately
VCF_minReIm minimum real and imaginary parts separately
VCF_absmaxReIm maximum absolute real and imaginary values separately
VCF_absminReIm minimum absolute real and imaginary values separately
VCF_absmax largest magnitude (absolute value; this is a real number)
VCF_absmin smallest magnitude
VCF_cabsmax complex number of largest magnitude
VCF_cabsmin complex number of smallest magnitude
VCF_sabsmax complex number for which the sum |Re| + |Im| is largest
VCF_sabsmin smallest complex number in terms of the sum |Re| + |Im|
VCF_absmaxind largest magnitude (absolute value) and its index
VCF_absminind smallest magnitude and its index
 
Sums, products, etc. are available by functions grouped as statistical building blocks and summarized in chapter 4.9

To determine the center of gravity of a vector, you have the choice between the following two functions:
 
VF_centerOfGravityIndcenter of gravity, returned as an interpolated element index
VF_centerOfGravityVcenter of gravity of a Y vector with explicitly given X axis

Back to Table of Contents 

4.8 Signal Processing:
Fourier Transforms and Related Topics

The following list of functions is available for signal processing applications:
 
VF_FFTtoC forward Fast Fourier Transform (FFT) of a real vector; the result is a cartesian complex vector
VF_FFT forward and backward FFT of a real vector; the result of the forward FFT is packed into a real vector of the same size as the input vector
VCF_FFT forward and backward FFT of a complex vector
MF_Rows_FFTFFT along the rows of a matrix; this function may be used for batch-processing of several vectors of identical size, stored as the rows of a matrix
MF_Cols_FFTFFT along the columns of a matrix; this function may be used for batch-processing of several vectors of identical size, stored as the columns of a matrix
VF_convolve
VF_convolvewEdit
convolution with a given response function
VF_deconvolve
VF_convolvewEdit
deconvolution, assuming a given response function
VF_filter spectral filtering
VF_spectrum spectral analysis
VF_xspectrum cross-spectral density of two signals (complex one-sided variant)
VF_xspectrumAbs cross-spectral density of two signals (absolute values)
VF_coherence coherence function between two signals
VF_autocorr autocorrelation function of a data array
VF_xcorr cross-correlation function of two arrays
VF_setRspEdit set default editing threshold for the filter in convolutions and deconvolutions (decides over the treatment of "lost" frequencies)
VF_getRspEdit retrieve the current default editing threshold

FFT and all FFT-based functions need additional buffer memory which they allocate and free internally. In order to allow this inefficiency to be avoided for multiple calls, all of these functions exist in an additional version, marked by the prefix VFb_, which takes a pointer to user-supplied buffer memory as an additional argument. The necessary size of this buffer memory is given for each function in its detailed description in FUNCREF.HTM.

Although they do not use Fourier transform methods, the functions VF_biquad (bi-quadratic audio filtering) and VF_smooth (crude form of frequency filtering which removes high-frequency noise) should be mentioned here.

Back to Table of Contents 

4.9 Statistical Functions and Building Blocks

The following collection of statistical functions is offered by OptiVec:
 
VF_sum sum of all elements
VI_fsum sum of all elements of an integer vector, accumulated as a floating point number in double or extended precision
VF_prod product of all elements
VF_ssq sum-of-squares of all elements
VF_sumabs sum of absolute values of all elements
VF_rms root-of-the-mean-square of all elements
VF_runsum running sum, also called "cumulative sum" or "inclusive sum-scan"
VF_runprod running product
VF_sumdevC sum over the deviations from a preset constant, sum( |Xi-C| )
VF_sumdevV sum over the deviations from another vector, sum( |Xi-Yi| )
VF_sumdevVwSaturation sum over the deviations from another vector, sum( |Xi-Yi| ) with saturation of possible overflow to HUGE_VAL
VF_subV_sumabs difference between two vectors and sum over the absolute values of the results
VF_avdevC average deviation from a preset constant, 1/N * sum( |Xi-C| )
VF_avdevV average deviation from another vector, 1 / N * sum( |Xi-Yi| )
VF_ssqdevC sum-of-squares of the deviations from a preset constant,
sum( (Xi - C)² )
VF_ssqdevV sum-of-squares of the deviations from another vector,
sum( (Xi - Yi)² )
VF_ssqdevVwSaturation sum-of-squares of the deviations from another vector with saturation of possible overflow to HUGE_VAL
VF_subV_ssq difference between two vectors and sum-of-squares over the results
VF_chi2 chi-square merit function
VF_chi2wSaturation chi-square merit function with saturation of possible overflow to HUGE_VAL
VF_subV_chi2 difference between two vectors and chi-square merit function
VF_chiabs "robust" merit function, similar to VF_chi2, but based on absolute instead of squared deviations
VF_chiabswSaturation The same as VF_chiabs, but with saturation of possible overflow to HUGE_VAL
VF_subV_chiabs difference between two vectors and chiabs merit function
VF_mean equally-weighted mean (or average) of all elements
VF_meanwW "mean with weights" of all elements
VF_meanabs equally-weighted mean (or average) of the absolute values of all elements
VF_selected_mean averages only those vector elements which fall into a specified range, thus allowing to exclude outlier points from the calculation of the mean
VF_varianceC variance of a distribution with respect to a preset constant value
VF_varianceCwW the same with non-equal weighting
VF_varianceV variance of one distribution with respect to another
VF_varianceVwW the same with non-equal weighting
VF_meanvar mean and variance of a distribution simultaneously
VF_meanvarwW the same with non-equal weighting
VF_median median of a distribution
VF_corrcoeff linear correlation coefficient of two distributions
VF_distribution histogram calculation - bins data into a discrete one-dimensional distribution function
VF_min_max_mean_stddev simultaneous calculation of the minimum, maximum, mean, and standard deviation of a one-dimensional distribution

Back to Table of Contents 

4.10 Data Fitting

Ranging from a simple linear regression to complex fitting problems involving multiple data sets and nonlinear functions with many adjustable parameters, OptiVec offers routines for virtually all practically occurring tasks of data fitting. As all of them, except for simple linear regression, rely on matrix methods, they actually form a part of MatrixLib. This means you have to #include <MFstd.h> (<MDstd.h>< MEstd.h>) or the unit MFstd, (MDstd, MEstd).

A detailed description of the various data-fitting concepts is given in chapter 13 of MATRIX.HTM. Therefore, at this place, the available X-Y fitting functions are only summarized in the following table:
 
VF_linregress equally-weighted linear regression on X-Y data
VF_linregresswW the same with non-equal weighting
VF_polyfit fitting of one X-Y data set to a polynomial
VF_polyfitwW the same for non-equal data-point weighting
VF_polyfitOdd fitting of one X-Y data set to a polynomial with odd terms only
VF_polyfitOddwW the same for non-equal data-point weighting
VF_polyfitEven fitting of one X-Y data set to a polynomial with even terms only
VF_polyfitEvenwW the same for non-equal data-point weighting
VF_linfit fitting of one X-Y data set to an arbitrary function linear in its parameters
VF_linfitwW the same for non-equal data-point weighting
VF_setLinfitNeglect set threshold to neglect (i.e. set equal to zero) a fitting parameter A[i], if its significance is smaller than the threshold
VF_getLinfitNeglect retrieve current significance threshold
VF_nonlinfit fitting of one X-Y data set to an arbitrary, possibly non-linear function
VF_nonlinfitwW the same for non-equal data-point weighting
VF_multiLinfit fitting of multiple X-Y data sets to one common linear function
VF_multiLinfitwW the same for non-equal data-point weighting
VF_multiNonlinfit fitting of multiple X-Y data sets to one common nonlinear function
VF_multiNonlinfitwW the same for non-equal data-point weighting
 

Back to Table of Contents 

4.11 Input and Output

VF_cprint Windows with MS Visual C++ or Borland / Embarcadero compiler:/u> print the elements of a vector to the screen (or "console" – hence the "c" in the name) into the current text window. The height and width of the text window are automatically detected. After printing one page, the user is prompted to continue. (Only for console applications)
Other Windows compilers and Linux: identical to VF_print.
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. The symbolic constant V_consoleWindowWidth (defined in <VecLib.h> or in the unit VecLib with a default value of 150) determines the linewidth, and no division into pages is made. (Only for console applications)
VF_fprint print a vector to a stream.
VF_chexprint Similar to VF_cprint, but printed in hexadecimal format.
VF_hexprint Similar to VF_print, but printed in hexadecimal format.
VF_fhexprint Similar to VF_fprint, but printed in hexadecimal format.
VF_write write data in ASCII format in a stream
VF_read read a vector from an ASCII file
VF_nwrite write n vectors of the same data type as the columns of a table into a stream
VF_nread read the columns of a table into n vectors of the same type
VF_store store data in binary format
VF_recall retrieve data in binary format

The following functions allow to modify the standard settings of VF_write,   VF_nwrite and VI_read
VF_setWriteFormat define a certain number format
VF_setWriteSeparate define a separation string between successive elements, written by VF_write
VF_setNWriteSeparate define a separation string between the columns written by VF_nwrite
V_setRadix define a radix different from the standard of 10 for the whole-number variants of the V.._read functions

Back to Table of Contents 

4.12 Graphics

VectorLib includes a range of data-plotting routines. Before any of them may be used, VectorLib graphics has to be initialized:
 
V_initPlot initialize VectorLib graphics functions. 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.
V_initPrint initialize VectorLib graphics functions and direct them to a printer. By default, one whole page is reserved for plotting. In order to change this, call V_setPlotRegion after V_initPrint.
V_setPlotRegion set a plotting region different from the default

VectorLib distinguishes between two sorts of plotting functions, AutoPlot and DataPlot. All AutoPlot functions (e.g., VF_xyAutoPlot) execute the following steps:

  1. define a viewport within the plotting region (which is either the default region or the one defined by calling V_setPlotRegion)
  2. clear the viewport
  3. generate a Cartesian coordinate system with suitably scaled and labeled axes
  4. subdivide the axes either linearly or logarithmically, according to the suffix of the AutoPlot function:
    V?_autoPlot (no suffix): both X and Y axis linear.
    V?_autoPlot_xlg_ylin: X axis logarithmic, Y axis linear.
    V?_autoPlot_xlg_ylg: both X and Y axis logarithmic.
    V?_autoPlot_xlin_ylg: X axis linear, Y axis logarithmic.
  5. plot the data according to the parameters passed to the function
All DataPlot functions execute only the last step. They assume that a coordinate system already exists from a previous call to any of the AutoPlot functions, to V_findAxes, or to V_drawAxes. 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.
To add text and lables, a new viewport must be defined by calling SetViewportOrgEx.

For all plotting functions, the different plot styles (symbols, lines, and colors), are specified as parameters, see VF_xyAutoPlot. Here is a list of the available AutoPlot and DataPlot routines:
 
VF_xyAutoPlot display an automatically-scaled plot of an X-Y vector pair
VF_yAutoPlot plot a single Y-vector, using the index as X-axis
VF_xy2AutoPlot plot two X-Y pairs at once, scaling the axes in such a way that both vectors fit into the same coordinate system
VF_y2AutoPlot the same for two Y-vectors, plotted against their indices
VF_xyDataPlot plot one additional set of X-Y data
VF_yDataPlot plot one additional Y vector over its index

Cartesian complex arrays are printed into the complex plane (the imaginary parts versus the real parts), using
 
VCF_autoPlot plot one cartesian complex vector
VCF_2AutoPlot plot two cartesian complex vectors simultaneously
VCF_dataPlot plot one additional cartesian complex vector

At present, there are no plotting functions for polar complex vectors included.
It is possible to draw more than one coordinate systems into a given window on the screen. The position of each coordinate system must be specified by the above-mentioned function V_setPlotRegion. "Hopping" between the different coordinate systems and adding new DataPlots after defining new viewports (e.g., for text output) is made possible by the following functions:
 
V_continuePlot go back to the viewport of the last plot and restore its scalings
V_getCoordSystem get a copy of the scalings and position of the current coordinate system
V_setCoordSystem restore the scalings and position of a coordinate system; these must have been stored previously, using V_getCoordSystem

Back to Table of Contents 


5. Error Handling

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.

The production libraries of OptiVec treat all mathematical errors (Overflow, Singularity, Domain/Range, Loss-of-Accuracy) "silently" and continue program execution with a corrected result.
The Debug libraries, on the other hand, indicate the occurrence of errors by emitting a message, in addition to correcting the result. As described below, the function V_setFPErrorHandling can be called in order to control which errors will lead to a message. The function V_setErrorEventFile allows to choose if the messages are to be emitted into a log file, to a popup window, or into a console text window.
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 are limits to the ability of protection mechanisms to catch floating-point errors. Especially the extended-precision versions, but also the double-precision versions do not have much of a "safety margin". 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.

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 Table of Contents

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, the 32-bit (but not the 64-bit) libraries of OptiVec offer 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_rampVI_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:
Example:
#define V_trapIntError 1
#include <VSIstd.h>
#include <VSImath.h>
.....
main() /* or WinMain(), or OwlMain() */
{
  siVector SI1, SI2;
  SI1 = VSI_vector( 1000 ); SI2 = VSI_vector( 1000 );
  V_setIntErrorHandling( ierrNote );
  VSI_ramp( SI1, 1000, 0, 50 ); /* an overflow will occur here! */
  V_setIntErrorHandling( ierrIgnore );
  VSI_mulC( SI2, SI1, 1000, 5 );
    /* here, even a whole series of overflows will occur; they are all ignored. */
  ....
}

Back to Table of Contents

5.3 Floating-Point Errors

All OptiVec 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) catch and handle mathematical errors. Overflow, singularity, and loss-of-precision errors are treated by setting the result to the default value indicated for each function in FUNCREF.HTM. DOMAIN / ERANGE errors lead to the result NAN (not-a-number).
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).

Debug libraries only: As has been mentioned above, one may call V_setFPErrorHandling in order to select which error types lead to a message and which may lead to program execution being broken off. The available options are set by the predefined constants fperrXXX:
OptionMeaning
fperrIgnoreTreat all floating-point errors silently
fperrNoteDOMAINNotify in case of DOMAIN / ERANGE errors
fperrAbortDOMAINNotify and break off in case of DOMAIN / ERANGE errors
fperrNoteSINGNotify in case of Singularities (divisions by 0)
fperrAbortSINGNotify and break off in case of Singularities
fperrNoteOVERFLOWNotify in case of Overflow
fperrAbortOVERFLOW  Notify and break off in case of Overflow
fperrNoteTLOSSNotify in case of Total Loss of Precision (e.g., at sin(1.e30))
fperrAbortTLOSSNotify and break off in case of Total Loss of Precision
fperrDefaultDefault setting = fperrAbortDOMAIN + fperrNoteSING + fperrNoteOVERFLOW
 
When calling V_setFPErrorHandling, combine these constants by the + or better 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 C/C++ or Pascal/Delphi functions handle errors.

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.

Back to Table of Contents

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 much less appropriate to us.)

Back to Table of Contents

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 (ScreenAndFile = 0), or additionally into a message box (ScreenAndFile = 1) or, for console programmes, to the screen as well (ScreenAndFile = 2). By calling V_setErrorEventFile( "NULL", 0 ) (C/C++) or V_setErrorEventFile( 'nil', 0 ) (Pascal/Delphi), you can even completely switch any messages off (if you decide that is a wise thing to do).

Note that this redirection of error messages is valid only for errors occurring in OptiVec routines. It is possible, however, for a user program to use the OptiVec function V_printErrorMsg for its own error messages.

Certain configurations of the compilers supported by OptiVec do not allow the full set of options described above. For some, either output into a message box is missing or output to the console screen. In these cases, an error message is displayed and the output redirected to the available other option.

Back to Table of Contents

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 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 usually read VLI_. Similarly, VFs_FFT or VFp_FFT will be substituted for VF_FFT, depending on the library and vector size. The reason for this behavior is that many functions share code and even names.

 

(00) OptiVec/CMATH not installed correctly
(must use INSTALL.EXE !)
Demo version only: Apparently, 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 copying the files from somewhere else, without using INSTALL.EXE. This is not possible, as INSTALL.EXE also starts the clock for the trial period. Install again, this time using INSTALL.EXE.

 

(0) Trial period for OptiVec/CMATH has expired!
Demo 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 one of two mistakes: Either the parameter size has not been initialized (and contains some garbage with high bits set), or there are "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.
* 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 > 4 GB not possible (32-bit).
* Looks like you are trying to allocate a vector whose size exceeds the maximum of 4 GB in 32-bit. It is about time to switch to 64-bit!

 

(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.

 

(5) X-values of table must be distinct.
The routines performing interpolations need the tables to be ordered according to their x-values. Each x-value may occur only once, as it is impossible for one and the same x-value to belong to different y-values.

 

(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 vector 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. While this error might be harmless (e.g., you forgot that you already freed a vector and try to free it again), it might also be the result of rather serious problems. For example, a memory leak might have occurred and led to the vector variable being overwritten. Use the debug library in order to detect vector or matrix dimension mismatches, which are the principal cause of memory leaks, when you program with OptiVec.

Back to Table of Contents

 

(21) Invalid dimension(s).
In one way or the other, the dimensions of input or output matrices do not meet the requirements.

 

(22) Matrix is singular.
In a function requiring regular input matrices, a singular matrix was encountered. Consider alternative functions, designed to handle (nearly) singular matrices.

 

(23) No convergence achieved.
Some iterative matrix methods may, in very rare cases, fail to achieve convergence.

 

(24) Only the first n elements of each row can be printed.
This error occurs with the matrix printing functions. The number of columns is too large for the available linewidth. The function automatically selects the maximum number of columns to be displayed and truncates the rows as needed.


6. Trouble-Shooting

In case of problems, please check first if OptiVec is correctly installed (see chapter 1.4). If this is the case, carefully check the following points whose violation would inevitably lead to failure. 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 Table of Contents


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, VUQstd, VUIstdStandard operations for unsigned integer vectors
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, VUQmath, VUImathArithmetical and mathematical functions for unsigned integer vectors
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.
OVXMATHA few non-vectorized math functions needed internally by other OptiVec functions; they are publically accessible (see chapter 9). C/C++: declares also the sine, cosec, and tangent tables for VF_sinrpi2 etc.
FSINTAB2, DSINTAB2, ESINTAB3,
FSINTAB3, DSINTAB3, ESINTAB3
sine tables (Pascal/Delphi only; for C/C++, they are in OVXMATH)
FCSCTAB2, DCSCTAB2, ECSCTAB3,
FCSCTAB3, DCSCTAB3, ECSCTAB3
cosecant tables (Pascal/Delphi only; for C/C++, they are in OVXMATH)
FTANTAB2, DTANTAB2, ETANTAB3,
FTANTAB3, DTANTAB3, ETANTAB3
tangent tables (Pascal/Delphi only; for C/C++, they are in OVXMATH)
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 Table of Contents


E N D

Copyright for OptiVec software and documentation
© 1996-2024 OptiCode – Dr. Martin Sander Software Dev.
All rights reserved!