![]() | CMATH
Version 6
for C/C++ and for Delphi |
OptiCode
Dr. Martin Sander Software Development Steinachstr. 9A D-69198 Schriesheim Germany http://www.optivec.com e-mail: optivec@gmx.de |
CMATH is available both separately and as a part of OptiVec. If you ordered or downloaded CMATH alone, please disregard all references to OptiVec in this documentation.
If you got CMATH as a part of OptiVec, you may wish to refer to HANDBOOK.HTM for a description of the basic principles of the OptiVec libraries and an overview over VectorLib, the first part of OptiVec. The second part, MatrixLib is described in MATRIX.HTM.
Chapter 1.2 of this file contains the licence terms for the Shareware 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 Shareware-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.com/download/CMDOCD.ZIP. |
Superior speed, accuracy and safety are achieved through the implementation in Assembly language (as opposed to the compiled or inline code of available complex C++ class libraries). Only for the most simple tasks, alternative inline C++ functions are used in the C++ version.
As far as the scope of CMATH overlaps with the complex class implementations of Visual C++, Borland C++, and Delphi, CMATH is a high-quality replacement for the latter, which are all awfully inefficient and inaccurate.
In contrast to the written-down-and-compiled textbook formulas of most other available complex libraries (including those coming with Visual C++ and the Borland compilers), the implementation of CMATH was guided by the following rules:
This documentation describes the CMATH implementations for
Here is a detailed description of how to switch from the complex classes of Borland C++ to the new implementation given by CMATH:
The data types fComplex, dComplex, eComplex, fPolar, dPolar, and ePolar are defined as synonyms for these classes.
In order to avoid the letter "L" (which is already over-used by long and unsigned long, extended is used as a synonym for long double in the Borland C++ version of CMATH. In the MSVC version, it is a synonym for double, as MSVC does not support 80-bit IEEE reals. Consequently, the complex data types of extended precision are named eComplex and ePolar. Thereby, the way is held open for a future inclusion of whole-number complex types into CMATH. Then, liComplex and ulComplex shall denote the complex types consisting of long int and unsigned long parts, respectively.
CMATH for Pascal/Delphi defines six complex data types:
type fComplex = record Re, Im: Single; 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;
The reason why the single-precision type gets the name fComplex instead of sComplex is that the letter "s" is already over-used by ShortInt and SmallInt in Pascal. Therefore, this name is derived from the C/C++ analogue of Single, which is float.
The CMATH-Pascal data types are binary compatible with those of the C/C++ versions.
The type-specific function names are the same as in the plain-C version. The syntax, however, is somewhat different, as complex numbers as return values could be implemented most efficiently by passed them as var arguments to the complex functions, e.g.
procedure cf_sin( var zy:fComplex; zx:fComplex );
The overloaded function names are the same as in the C++ version. Here, the results are treated as true return values, e.g.
function sin( zx:fComplex ): fComplex;
This is the Shareware version of CMATH ("SOFTWARE").
It may be used under the following licence terms:
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 CMATH 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.
The full versions (both the commercial and the educational editions) of CMATH
You may also order by e-mail to register@shareit.com.
US customers can also contact ShareIt! by telephone 1-724-850-8186 or FAX 1-724-850-8189 (only for orders, please).
Note the program No.:
commercial | educational | |
CMATH for Embarcadero / Borland C/C++ | 101353 | 102655 |
CMATH for Microsoft Visual C++ | 103422 | 103441 |
CMATH for Delphi | 103844 | 103860 |
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 send a print-out of this order form to
OptiCode - Dr. Martin Sander Software Dev.
Steinachstr. 9A
D-69198 Schriesheim
Germany
FAX +49 - 6203 - 92 53 96
For any other questions related to ordering CMATH, please contact us at: optivec@gmx.de
This is a single copy license for CMATH ("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:
If you got CMATH as a part of OptiVec, you should read chapter 1.4 of HANDBOOK.HTM instead of the remainder of the present paragraph. If you have already read that, continue with chapter 2, or go back to the Table of Contents.
To install CMATH, please follow these steps:
Processor | CMATH library |
486DX/Pentium | CMATHF4W.LIB | newer processors (at least Pentium III) | CMATHF6W.LIB |
Runtime Library | CMATH base library (all VC++-versions) | Visual Studio 2005 only | Visual Studio 2008 or 2010 |
Win32, single-thread debug | CMVCSD.LIB | ---- | ---- |
Win32, single-thread release | CMVCSR.LIB | ---- | ---- |
Win32, multi-thread debug | CMVCMTD.LIB | CMVC8MTD.LIB | CMVC9MTD.LIB |
Win32, multi-thread release | CMVCMTR.LIB | CMVC8MTR.LIB | CMVC9MTR.LIB |
Win32, multi-thread DLL debug | CMVCMDD.LIB | CMVC8MDD.LIB | CMVC9MDD.LIB |
Win32, multi-thread DLL release | CMVCMDR.LIB | CMVC8MDR.LIB | CMVC9MDR.LIB |
Win64, multi-thread debug | CMVCx64MTD.LIB | ||
Win64, multi-thread release | CMVCx64MTR.LIB | ||
Win64, multi-thread DLL debug | CMVCx64MDD.LIB | ||
Win64, multi-thread DLL release | CMVCx64MDR.LIB |
Processor | 32-bit CMATH library | 64-bit CMATH library |
486DX/Pentium | CMVC4.LIB | ---- |
newer processors (at least Pentium III) | CMVC6.LIB | ---- |
latest processors (Core2xxx, i3, i5, i7, AMDx64) | ---- | CMVC64_8.LIB |
In C++ and Delphi, synonyms are defined for all these functions. The synonyms do not have a prefix, since the data type information is implicitly handled by the compiler. The overloaded function names are mostly identical to those found in the complex class libraries (if the respective function exists there). Note, however, that the member function polar had to be replaced by magargtoc, as the name "polar" is now reserved for the polar classes.
C++ only: If you wish to use the C function names in your C++ modules, be sure to include
In the following, we denote the complex classes by by their short names, fComplex, fPolar, etc. In C++, you can always use the template nomenclature instead, writing "complex<float>" wherever "fComplex" is written here, and so on for all other complex types and classes.
Complex numbers are initialized by separately assigning a value to the imaginary and real parts or to the Mag and Arg parts, e.g.:
Pascal/Delphi:
For double-precision complex numbers, use dcplx and dpolr, for extended-precision complex numbers, use ecplx and epolr.
Interconversions between the various complex types are performed via the functions:
Similarly to the constructors fComplex() and fPolar(), also dComplex(), dPolar(), eComplex, and ePolar() exist in overloaded versions performing the same tasks for the classes dComplex, dPolar, eComplex, and ePolar, respectively. As described above for the C/Pascal/Delphi versions, OVERFLOW errors in the course of down-conversions are silently cured, without calling _matherr.
The conversion between cartesian and polar format involves transcedental functions and is, therefore, quite time-consuming. It is true that multiplications are faster in polar coordinates, whereas additions are much faster in Cartesian. The difference, however, is so much smaller than the cost of switching back and forth between the different representations, that we recommend you stay in general with the cartesian format. Only in the following cases, the conversion really makes sense:
C++, cartesian-complex classes:
Delphi 2006 or higher, cartesian-complex types:
Since it is only C++ and Delphi, but neither plain-C nor Pascal, which allows overloaded arithmetic operators, all arithmetic operations of complex numbers are implemented additionally as functions which may be called from C/Pascal/Delphi as well as C++ modules: The assignment operator "=" or ":=" is the only operator defined also in plain-C and Pascal/Delphi for complex numbers.
As noted above, the exponential and logarithm functions provide a natural transition between cartesian and polar coordinates. While there are exp and log functions for fComplex as argument and as return value, cf_exptop takes an fComplex argument and returns fPolar. In the opposite direction, pf_logtoc takes an fPolar argument and returns fComplex.
In contrast to the arithmetic operations, all mathematical functions and all data-type interconversions perform a tight error checking. All error messages eventually generated use the C/Pascal name (rather than the overloaded C++/Delphi name) of the failing function.
If you got CMATH as a part of OptiVec, you should read chapter 5 of HANDBOOK.HTM rather than the present chapter.
You might wish to circumvent this. To this end, OptiVec and CMATH provide the function V_setErrorEventFile. This function needs as arguments the desired name of your event file and a switch named ScreenAndFile which decides if you wish to have error messages printed simultaneously into the file and onto the screen (ScreenAndFile = TRUE (non-zero)) or exclusively into the file (ScreenAndFile = FALSE (0)).
Example: Note that this redirection of error messages is valid only for errors occurring in OptiVec (CMATH) routines. If you wish to do so, however, there is a way in C/C++ to extend the redirection also to the "non-OptiVec" functions: you may modify _matherr and _matherrl such that the statement
For example, your _matherr function (matherr - without the leading underbar - for Borland C++ 3.0 and 3.1) might look like the following one:
float cf_abs( fComplex __z );
float pf_abs( fPolar __p );
fComplex cf_acos( fComplex __z );
fComplex cf_add( fComplex __x, fComplex __y );
fComplex cf_addRe( fComplex __x, float __yRe );
float cf_arg( fComplex __z );
float pf_arg( fPolar __z );
fComplex cf_asin( fComplex __z );
fComplex cf_atan( fComplex __z );
eComplex cdtoce( dComplex __zd );
fComplex cdtocf( dComplex __zd );
dPolar cdtopd( dComplex __zd );
ePolar cdtope( dComplex __zd );
fPolar cdtopf( dComplex __zd );
dComplex cetocd( eComplex __ze );
fComplex cetocf( eComplex __ze );
dPolar cetopd( eComplex __ze );
ePolar cetope( eComplex __ze );
fPolar cetopf( eComplex __ze );
dComplex cftocd( fComplex __zf );
eComplex cftoce( fComplex __zf );
dPolar cftopd( fComplex __zf );
ePolar cftope( fComplex __zf );
fPolar cftopf( fComplex __zf );
fComplex cf_conj( fComplex __z );
fPolar pf_conj( fPolar __p );
fComplex cf_cos( fComplex __z );
fComplex cf_cosh( fComplex __z );
fComplex cf_cubic( fComplex __z );
fPolar pf_cubic( fPolar __p );
fComplex cf_div( fComplex __x, fComplex __y );
fPolar pf_div( fPolar __x, fPolar __y );
fComplex cf_divRe( fComplex __x, float __yRe ); /* x / yRe */
fPolar pf_divRe( fPolar __x, float __yRe ); /* x / yRe */
fComplex cf_divrRe( fComplex __x, float __yRe ); /* yRe / x */
fPolar pf_divrRe( fPolar __x, float __yRe ); /* yRe / x */
fComplex cf_exp( fComplex __z );
fPolar cf_exptop( fComplex __z );
fComplex fcplx( float __ReVal, float __ImVal);
fPolar fpolr( float __MagVal, float __ArgVal);
float cf_imag( fComplex __z );
float pf_imag( fPolar __p );
fComplex cf_inv( fComplex __z );
fPolar pf_inv( fPolar __p );
fComplex cf_ipow( fComplex __z, int __exponent );
fPolar pf_ipow( fPolar __p, int __exponent );
fComplex cf_ln( fComplex __z );
fComplex pf_lntoc( fPolar __p );
fComplex cf_log( fComplex __z );
fComplex pf_logtoc( fPolar __p );
fComplex cf_log2( fComplex __z );
fComplex pf_log2toc( fPolar __p );
fComplex cf_log10( fComplex __z );
fComplex pf_log10toc( fPolar __p );
fComplex cf_magargtoc( float __mag, float __angle );
fComplex cf_mul( fComplex __x, fComplex __y );
fPolar pf_mul( fPolar __x, fPolar __y );
fComplex cf_mulRe( fComplex __x, float __yRe );
fPolar pf_mulRe( fPolar __x, float __yRe );
fComplex cf_neg( fComplex __z );
fPolar pf_neg( fPolar __p );
float cf_norm( fComplex __z );
float pf_norm( fPolar __p );
dComplex pdtocd( dPolar __pd );
eComplex pdtoce( dPolar __pd );
fComplex pdtocf( dPolar __pd );
ePolar pdtope( dPolar __pd );
fPolar pdtopf( dPolar __pd );
dComplex petocd( ePolar __pe );
eComplex petoce( ePolar __pe );
fComplex petocf( ePolar __pe );
dPolar petopd( ePolar __pe );
fPolar petopf( ePolar __pe );
dComplex pftocd( fPolar __pf );
eComplex pftoce( fPolar __pf );
fComplex pftocf( fPolar __pf );
dPolar pftopd( fPolar __pf );
ePolar pftope( fPolar __pf );
fComplex cf_polar( float mag, float arg ); /* same as cf_magargtoc */
fComplex cf_pow( fComplex __base, fComplex __exponent );
fComplex cf_powReBase( float __base, fComplex __exponent );
fComplex cf_powReExpo( fComplex __base, float __exponent );
fPolar pf_powReExpo( fPolar __base, float __exponent );
fComplex cf_quartic( fComplex __z );
fPolar pf_quartic( fPolar __p );
float cf_real( fComplex __z );
float pf_real( fPolar __p );
fComplex cf_sin( fComplex __z );
fComplex cf_sinh( fComplex __z );
fComplex cf_square( fComplex __z );
fPolar pf_square( fPolar __p );
fComplex cf_sqrt( fComplex __z );
fPolar pf_sqrt( fPolar __p );
fComplex cf_sub( fComplex __x, fComplex __y );
fComplex cf_subRe( fComplex __x, float __yRe ); /* x - yRe */
fComplex cf_subrRe( fComplex __x, float __yRe ); /* yRe - x */
fComplex cf_tan( fComplex __z );
fComplex cf_tanh( fComplex __z );
float abs( fPolar _p );
fComplex acos( fComplex _z );
function add( zx, zy:fComplex ): fComplex;
float arg( fComplex _z );
float arg( fPolar _p );
fComplex asin( fComplex _z );
fComplex atan( fComplex _z );
fComplex conj( fComplex _z );
fPolar conj( fPolar _p );
fComplex cos( fComplex _z );
fComplex cosh( fComplex _z );
fComplex cubic( fComplex _z );
fPolar cubic( fPolar _p );
function divide( zx, zy:fComplex ): fComplex;
function divRe( zx:fComplex; yRe:Single ): fComplex;
fComplex exp( fComplex _z );
fPolar exptop( fComplex _z );
fComplex fComplex( float Re_part, float Im_part=0 );
float imag(); // to be used as zim = z.imag();
float imag( fPolar _p );
fPolar inv( fPolar _p );
fComplex ipow( fComplex __base, int __expon );
fPolar ipow( fPolar __base, int __expon );
fComplex ln( fComplex _z );
fComplex lntoc( fPolar _p );
fComplex log( fComplex _z );
fComplex logtoc( fPolar _p );
fComplex log2( fComplex _z );
fComplex log2toc( fPolar _p );
fComplex log10( fComplex _z );
fComplex log10toc( fPolar _p );
fComplex magargtoc( float _mag, float _angle );
function mul( zx, zy:fComplex ): fComplex;
function mulRe( zx:fComplex; yRe:Single ): fComplex;
fComplex neg( fComplex _z );
fPolar neg( fPolar _p );
float norm( fComplex _z );
float norm( fPolar _p );
fComplex pow( fComplex __base, fComplex __expon);
fComplex powReBase( float __base, fComplex __expon );
fComplex powReExpo( fComplex __base, float __expon );
fPolar powReExpo( fPolar __base, float __expon );
fPolar principal( fPolar _p );
fComplex quartic( fComplex _z );
fPolar quartic( fPolar _p );
float z.real(); // to be used as zre = z.real();
float real( fPolar _p );
fPolar reimtop( float _re, float _im );
fComplex sin( fComplex _z );
fComplex sinh( fComplex _z );
fComplex sqrt( fComplex _z );
fPolar sqrt( fPolar _p );
fComplex square( fComplex _z );
fPolar square( fPolar _z );
function sub( zx, zy:fComplex ): fComplex;
fComplex tan( fComplex _z );
fComplex tanh( fComplex _z );
2.1. Initialization of Complex Numbers
z.Re = 3.0; z.Im = 5.7;
p.Mag = 8.8; p.Arg = 3.14;
(Of course, for Pascal/Delphi, the assignment operator is written ":=").
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 );
fcplx( z, 3.0, 5.7 );
fpolr( p, 3.0, 5.7 );
2.2. Data-Type Interconversions
cftocd, cdtocf, cftoce, cetocf, cdtoce, cetocd up- or down-conversion of accuracy within the cartesian-complex types pftopd, pdtopf, pftope, petopf, pdtope, petopd up- or down-conversion of accuracy within the polar-complex types cftopf, cftopd, cftope,
cdtopf, cdtopd, cdtope,
cetopf, cetopd, cetopeconversion from cartesian into polar complex pftocf, pftocd, pftoce,
pdtocf, pdtocd, pdtoce,
petocf, petocd, petoceconversion from polar into cartesian complex
OVERFLOW errors in the course of down-conversions are silently cured: program execution is continued with the largest value possible.
C++ only:
For C++ modules, there are several overloaded constructors as an alternative to the above functions:
basic forms:
fComplex fComplex( float RePart, float ImPart=0 );
fComplex fComplex( dComplex );
fComplex fComplex( eComplex );
fPolar fPolar( float MagPart, float ArgPart=0 );
fPolar fPolar( dPolar );
fPolar fPolar( ePolar );
interconversion cartesian <--> polar:
fComplex fComplex( fPolar );
fComplex fComplex( dPolar );
fComplex fComplex( ePolar );
fPolar fPolar( fComplex );
fPolar fPolar( dComplex );
fPolar fPolar( eComplex );
A special constructor for polar numbers is
fPolar pf_principal( fPolar __p );
and, for C++ only, its overloaded form for two separate real input numbers
fPolar principal( float Mag, float Arg );
These functions reduce the input Arg to the range -p < Arg <= +p. 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.
Please note that these are the only polar functions reducing the output to the principal value. All others accept and return arguments whose angles may fall outside this range.
2.3 Basic Complex Operations
The following basic complex operations are defined in CMATH:
cartesian C/Pascal/Delphi function polar C/Pascal/Delphi function
overloaded C++/Delphi function explanation cf_conj pf_conj
conj complex-conjugate form cf_neg pf_neg
neg (or -) negation cf_real pf_real
real extraction of the real part cf_imag pf_imag
imag extraction of the imaginary part cf_magargtoc N.A.
magargtoc conversion of polar coordinates, entered as separate real numbers, into cartesian format N.A. pf_reimtop
reimtop conversion of complex coordinates, entered as separate real numbers, into polar format cf_abs pf_abs
abs absolute value (magnitude of the pointer in the complex plane; this
is treated as a math function with error handling) cf_arg pf_arg
arg argument (angle of the pointer in the complex plane) cf_norm pf_norm
norm norm (defined here as the square of the absolute value) N.A. pf_principal
principal principal value, with -p < Arg <= +p
(The double and extended-precision versions are exactly analogous to the cf_ / pf_ version)
2.4 Arithmetic Operations
Only C++ or Delphi from version 2006 on: Arithmetic operators are available for all complex classes / data types. They exist also for "mixed" arguments, where one argument is complex, the other real and where the arguments are of different floating-point accuracies.
+ - * / += -= *= /= == !=
C++, polar-complex classes:
* / *= /= == !=
+ - * / = <>
Delphi 2006+, polar-complex types:
* / = <>
Delphi before v2006 only: Instead of the operators defined for the more recent Delphi versions, you can use the following functions:
add sub mul divide
They work for two complex arguments or for one complex and one real argument.
Cartesian Polar
cf_add N.A.
addition of two complex numbers cf_addRe N.A.
addition of a complex number and a real number cf_sub N.A.
subtraction of two complex numbers (first operand minus the second operand) cf_subRe N.A.
subtraction of a real number from a complex number cf_subrRe N.A.
subtraction of a complex number from a real number cf_mul pf_mul
multiplication of two complex numbers cf_mulRe pf_mulRe
multiplication of a complex number and a real number cf_div pf_div
division of two complex numbers (first operand divided by the second operand) cf_divRe pf_divRe
division of a complex number by a real number cf_divrRe pf_divrRe
division of a real number by a complex number
(similarly the double- and extended-precision versions)
2.5 Mathematical Functions
CMATH contains all mathematical functions you would usually find in the complex class libraries of C++, along with several additional ones:
cartesian C/Pascal/Delphi function polar C/Pascal/Delphi function overloaded C++ function
formula explanation cf_abs pf_abs abs
ry = | zx | absolute value cf_acos N.A. acos
zy = acos( zx ) arcus cosine function cf_asin N.A. asin
zy = asin( zx ) arcus sine function cf_atan N.A. atan
zy = atan( zx ) arcus tangent function cf_cos N.A. cos
zy = cos( zx ) cosine cf_cosh N.A. cosh
zy = cosh( zx ) hyperbolic cosine cf_cubic pf_cubic cubic
zy = zx3 third power cf_exp cf_exptop exp
zy = exp( zx ) exponential function cf_inv pf_inv inv
zy = 1.0 / zx inverse cf_ipow pf_ipow ipow
zy = zxn integer power cf_ln pf_lntoc ln
zy = ln( zx ) natural logarithm cf_log pf_logtoc log
zy = ln( zx ) identical to cf_ln, pf_lntoc, ln cf_log2 pf_log2toc log2
zy = lb( zx ) binary logarithm cf_log10 pf_log10toc log10
zy = lg( zx ) decadic logarithm cf_pow N.A. pow
zy = zxzexp arbitrary power cf_powReBase N.A. pow, powReBase
zy = rzx real base to complex power cf_powReExpo pf_powReExpo pow, powReExpo
zy = zxr real power of complex base cf_quartic pf_quartic quartic
zy = zx4 fourth power cf_sin N.A. sin
zy = sin( zx ) sine cf_sinh N.A. sinh
zy = sinh( zx ) hyperbolic sine cf_square pf_square square
zy = zx2 square cf_sqrt pf_sqrt sqrt
zy = sqrt( zx ) square root cf_tan N.A. tan
zy = tan( zx ) tangent cf_tanh N.A. tanh
zy = tanh( zx ) hyperbolic tangent 3. Error Handling
3.1 General Error Handling of Complex Functions
The error handling of complex functions follows the rules employed generally also for real-number functions and operations. For all arithmetic operations, the design of the algorithms eliminates the danger of failure due to irregular intermediate results. Overflowing or otherwise irregular final results, however, will lead to a hardware interrupt being generated and, as a consequence, to a program abort.
3.1.1 C/C++ Specifics
All error conditions in CMATH math functions are handled via _matherr (for fComplex, fPolar, dComplex, and dPolar functions) and _matherrl (for eComplex and ePolar functions; Borland C++ only). The real or Mag part of the complex argument, causing an error is stored in e->x and the imaginary or Arg part in e->y.
Borland C++ 16-bit programs only:
As mentioned already in chapter 2, Borland has changed the name of the error-handling function matherr (without leading underbar), used in the versions 3.x, into _matherr (with a leading underbar), from version 4.0 on.
In order to make CMATH compatible with both the older and the later versions of Borland C++, the following way of error handling was adopted:
In case of an error, all CMATH functions call primarily matherr (as in the older versions of Borland C++). A macro NEWMATHERR provides for the necessary redirection of these calls to _matherr, if a later version of Borland C++ is used. Therefore, NEWMATHERR must be called once (!) in any program using CMATH, after the inclusion of <cmath.h> or <newcplx.h>. The best place is the module containing the main(), WinMain(), or OWLMain() function, after the header:
#include <cmath.h> /* or <newcplx.h> */
#include ...
NEWMATHERR
......
main()
{ ... }
3.1.2 Pascal/Delphi Specifics
How CMATH handles floating-point errors in the complex math functions is defined by a call to V_setFPErrorHandling. A number of pre-defined constants fperrXXX is available for the construction of the desired error-handling mode:
Constant Value Meaning fperrIgnore 0 Ignore all floating-point errors: handle them silently, do not print a message, continue program execution fperrNoteDOMAIN $0001 Print a message in case of a DOMAIN error fperrNoteSING $0002 Print a message in case of a SING error fperrNoteOVERFLOW $0003 Print a message in case of an OVERFLOW error fperrNoteTLOSS $0004 Print a message in case of a TLOSS error fperrAbortDOMAIN $0101 Abort program in case of a DOMAIN error fperrAbortSING $0202 Abort program in case of a SING error fperrAbortOVERFLOW $0303 Abort program in case of an OVERFLOW error fperrAbortTLOSS $0404 Abort program in case of a TLOSS error fperrDefaultHandling $0107 Same as fperrAbortDOMAIN or fperrNoteSING or fperrNoteOVERFLOW
Example:
V_setFPErrorHandling( fperrAbortDOMAIN + fperrAbortSING + fperrAbortOVERFLOW + fperrNoteTLOSS );
In this example, program execution will be aborted (with the appropriate message) in the case of the most severe errors, DOMAIN and SING. In the case of OVERFLOW and TLOSS errors, a warning will be displayed, but program execution will be continued with default results set by the respective functions where the errors occur. The repeated occurrence
of the same type of error within one and the same function will lead to only one message being generated. Subsequent errors will be treated silently.
3.2 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.
V_setErrorEventFile( "MyLogFil.TXT", 0 ); /* C/C++ */
V_setErrorEventFile( 'MyLogFil.TXT', FALSE ); (* Pascal/Delphi *)
Here, you will get all subsequent error messages only into your log file, MyLogFil.TXT and no messages on the screen. The default, i.e., printing error messages to the screen, is restored by V_closeErrorEventFile. (That function does not take any arguments and does not return anything.)
return 0;
(which signals an unresolved error) is replaced by the sequence
V_noteError( e->name, e->type ); return 1;
Thereby the task of printing the error message for unresolved errors is passed to the OptiVec function V_noteError which shall check if an error event file was defined or not and direct its output to the desired place. Keep in mind that it is the return value of _matherr which decides if an error message is printed by the default error handler of your compiler. Thus, after the call to V_noteError, the printing of the default error messages is by-passed by returning "1". (Also, do not forget that OptiVec / CMATH uses your _matherr routine to determine which errors you accept and which not!)
#include <math.h>
int _matherr( struct exception *e) /* "_exception" for MSVC */
{
if( (e->type == UNDERFLOW) || (e->type == TLOSS) ) ; /* ignore */
else /* all other errors deserve at least notice */
{
V_noteError( e->name, e->type );
if (e->type == DOMAIN) exit(1); /* really fatal */
}
return 1;
}
(Of course, if you decide to change _matherr, do not forget to change _matherrl in the same way, if you are using Borland C++!).
4. Syntax Reference
Except for the data-type conversion functions, only the float / fComplex / fPolar syntax is given. The syntax of the functions for double and extended precisions is exactly analogous.
If you chose the "classic" class complex, this is also similar. Just replace "float" by "double" and "fComplex" by "complex". No polar functions are available in the "classic" class complex, neither do any of the type-casting operators and interconversion functions exist, if there is only one type.
4.1 Plain-C, Pascal/Delphi Functions
For the functions of double / dComplex / dPolar and extended / eComplex / ePolar precision, the prefixes are cd_, pd_, ce_, and pe_, respectively.
function cf_abs( zx:fComplex ): Single;
function pf_abs( px:fPolar ): Single;
procedure cf_acos( var zy:fComplex; zx:fComplex );
procedure cf_add( var zz:fComplex; zx, zy:fComplex );
procedure cf_addRe( var zz:fComplex; zx:fComplex; yRe:Single );
function cf_arg( zx:fComplex ): Single;
function pf_arg( px:fPolar ): Single;
procedure cf_asin( var zy:fComplex; zx:fComplex );
procedure cf_atan( var zy:fComplex; zx:fComplex );
procedure cdtoce( var zy:eComplex; zx:dComplex );
procedure cdtocf( var zy:fComplex; zx:dComplex );
procedure cdtopd( var py:dPolar; zx:eComplex );
procedure cdtope( var py:ePolar; zx:eComplex );
procedure cdtope( var py:fPolar; zx:eComplex );
procedure cetocd( var zy:dComplex; zx:eComplex );
procedure cetocf( var zy:fComplex; zx:eComplex );
procedure cetopd( var py:dPolar; zx:eComplex );
procedure cetope( var py:ePolar; zx:eComplex );
procedure cetopf( var py:fPolar; zx:eComplex );
procedure cftocd( var zy:dComplex; zx:fComplex );
procedure cftoce( var zy:eComplex; zx:fComplex );
procedure cftopd( var py:dPolar; zx:fComplex );
procedure cftope( var py:ePolar; zx:fComplex );
procedure cftopf( var py:fPolar; zx:fComplex );
procedure cf_conj( var zy:fComplex; zx:fComplex );
procedure pf_conj( var py:fPolar; px:fPolar );
procedure cf_cos( var zy:fComplex; zx:fComplex );
procedure cf_cosh( var zy:fComplex; zx:fComplex );
procedure cf_cubic( var zy:fComplex; zx:fComplex );
procedure pf_cubic( var py:fPolar; px:fPolar );
procedure cf_div( var zz:fComplex; zx, zy:fComplex );
procedure pf_div( var pz:fPolar; px, py:fPolar );
procedure cf_divRe( var zz:fComplex; zx:fComplex; yRe:Single );
procedure pf_divRe( var pz:fPolar; px:fPolar; yRe:Single );
procedure cf_divrRe( var zz:fComplex; zx:fComplex; yRe:Single );
procedure pf_divrRe( var pz:fPolar; px:fPolar; yRe:Single );
procedure cf_exp( var zy:fComplex; zx:fComplex );
procedure cf_exptop( var py:fPolar; zx:fComplex );
procedure fcplx( var zy:fComplex; xRe, xIm:Single );
procedure fpolr( var py:fPolar; xMag, xArg:Single );
function cf_imag( zx:fComplex ): Single;
function pf_imag( px:fPolar ): Single;
procedure cf_inv( var zy:fComplex; zx:fComplex );
procedure pf_inv( var py:fPolar; zx:fComplex );
procedure cf_ipow( var zy:fComplex; zx:fComplex; exponent:Integer );
procedure pf_ipow( var py:fPolar; px:fPolar; exponent:Integer );
procedure cf_ln( var zy:fComplex; zx:fComplex );
procedure pf_lntoc( var zy:fComplex; zx:fPolar );
procedure cf_log( var zy:fComplex; zx:fComplex );
procedure pf_logtoc( var zy:fComplex; zx:fPolar );
procedure cf_log2( var zy:fComplex; zx:fComplex );
procedure pf_log2toc( var zy:fComplex; zx:fPolar );
procedure cf_log10( var zy:fComplex; zx:fComplex );
procedure pf_log10toc( var zy:fComplex; zx:fPolar );
procedure cf_magargtoc( var zy:fComplex; mag, angle:Single );
procedure cf_mul( var zz:fComplex; zx, zy:fComplex );
procedure pf_mul( var zz:fPolar; zx, zy:fPolar );
procedure cf_mulRe( var zz:fComplex; zx:fComplex; yRe:Single );
procedure pf_mulRe( var zz:fPolar; zx:fPolar; yRe:Single );
procedure cf_neg( var zy:fComplex; zx:fComplex );
procedure pf_neg( var py:fPolar; px:fPolar );
function cf_norm( zx:fComplex ): Single;
function pf_norm( px:fPolar ): Single;
procedure pdtocd( var zy:dComplex; px:dPolar );
procedure pdtoce( var zy:eComplex; px:dPolar );
procedure pdtocf( var zy:fComplex; px:dPolar );
procedure pdtope( var zy:ePolar; zx:dPolar );
procedure pdtopf( var zy:fPolar; zx:dPolar );
procedure petocd( var zy:dComplex; px:ePolar );
procedure petoce( var zy:eComplex; px:ePolar );
procedure petocf( var zy:fComplex; px:ePolar );
procedure petopd( var zy:dPolar; zx:ePolar );
procedure petopf( var zy:fPolar; zx:ePolar );
procedure pftocd( var zy:dComplex; px:fPolar );
procedure pftoce( var zy:eComplex; px:fPolar );
procedure pftocf( var zy:fComplex; px:fPolar );
procedure pftopd( var zy:dPolar; zx:fPolar );
procedure pftope( var zy:ePolar; zx:fPolar );
procedure cf_polar( var zy:fComplex; mag, arg:Single );
procedure cf_pow( var zy:fComplex; zx:fComplex; exponent:Integer );
procedure cf_powReBase( var zy:fComplex; base:Single; exponent:fComplex );
procedure cf_powReExpo( var zy:fComplex; zx:fComplex; exponent:Single );
procedure pf_powReExpo( var py:fPolar; px:fPolar; exponent:Single );
procedure cf_quartic( var zy:fComplex; zx:fComplex );
procedure pf_quartic( var py:fPolar; zx:fPolar );
function cf_real( zx:fComplex ): Single;
function pf_real( px:fPolar ): Single;
procedure cf_sin( var zy:fComplex; zx:fComplex );
procedure cf_sinh( var zy:fComplex; zx:fComplex );
procedure cf_square( var zy:fComplex; zx:fComplex );
procedure pf_square( var py:fPolar; zx:fPolar );
procedure cf_sqrt( var zy:fComplex; zx:fComplex );
procedure pf_sqrt( var py:fPolar; px:fPolar );
procedure cf_sub( var zz:fComplex; zx, zy:fComplex );
procedure cf_subRe( var zz:fComplex; zx:fComplex; yRe:Single );
procedure cf_subrRe( var zz:fComplex; zx:fComplex; yRe:Single );
procedure cf_tan( var zy:fComplex; zx:fComplex );
procedure cf_tanh( var zy:fComplex; zx:fComplex );
4.2 Overloaded C++/Delphi Functions
float abs( fComplex _z );
function abs( zx:fComplex ): Single;
function abs( px:fPolar ): Single;
function acos( zx:fComplex ): fComplex;
function add( zx:fComplex; yRe:Single ): fComplex;
function add( yRe:Single; zx:fComplex ): fComplex;
function addRe( zx:fComplex; yRe:Single ): fComplex;
function arg( zx:fComplex ): Single;
function arg( px:fPolar ): Single;
function asin( zx:fComplex ): fComplex;
function atan( zx:fComplex ): fComplex;
function conj( zx:fComplex ): fComplex;
function conj( px:fPolar ): fPolar;
function cos( zx:fComplex ): fComplex;
function cosh( zx:fComplex ): fComplex;
function cubic( zx:fComplex ): fComplex;
function cubic( px:fPolar ): fPolar;
function divide( zx:fComplex; yRe:Single ): fComplex;
function divide( yRe:Single; zx:fComplex ): fComplex;
function divide( px, py:fPolar ): fPolar;
function divide( px:fPolar; yRe:Single ): fPolar;
function divide( yRe:Single; px:fPolar ): fPolar;
function divRe( px:fPolar; yRe:Single ): fPolar;
function divrRe( zx:fComplex; yRe:Single ): fComplex;
function divrRe( px:fPolar; yRe:Single ): fPolar;
function exp( zx:fComplex ): fComplex;
function exptop( zx:fComplex ): fPolar;
fComplex fComplex( dComplex cd );
fComplex fComplex( eComplex ce ); // type-casting constructors
fComplex fComplex( fPolar pf ); // interconversion from polar
fComplex fComplex( dPolar pd );
fComplex fComplex( ePolar pe );
float imag( fComplex _z ); // to be used as zim = imag( z );
function imag( zx:fComplex ): Single;
function imag( px:fPolar ): Single;
fComplex inv( fComplex _z );
function inv( zx:fComplex ): fComplex;
function inv( px:fPolar ): fPolar;
function ipow( zx:fComplex; exponent:Integer ): fComplex;
function ipow( px:fPolar; exponent:Integer ): fPolar;
function ln( zx:fComplex ): fComplex;
function lntoc( px:fPolar ): fComplex;
function log( zx:fComplex ): fComplex;
function logtoc( px:fPolar ): fComplex;
function log2( zx:fComplex ): fComplex;
function log2toc( px:fPolar ): fComplex;
function log10( zx:fComplex ): fComplex;
function log10toc( px:fPolar ): fComplex;
function magargtoc( mag, angle:Single ): fComplex;
function mul( zx:fComplex; yRe:Single ): fComplex;
function mul( yRe:Single; zx:fComplex ): fComplex;
function mul( px, py:fPolar ): fPolar;
function mul( px:fPolar; yRe:Single ): fPolar;
function mul( yRe:Single; px:fPolar ): fPolar;
function mulRe( px:fPolar; yRe:Single ): fPolar;
function neg( zx:fComplex ): fComplex;
function neg( px:fPolar ): fPolar;
function norm( zx:fComplex ): Single;
function norm( px:fPolar ): Single;
fComplex pow( float __base, fComplex __expon);
fComplex pow( fComplex __base, float __expon );
function pow( zx, exponent:fComplex ): fComplex;
function pow( zx:fComplex; exponent:Single ): fComplex;
function pow( base:Single; exponent:fComplex ): fComplex;
function pow( px:fPolar; exponent:Single ): fPolar;
function powReBase( base:Single; exponent:fComplex ): fComplex;
function powReExpo( zx:fComplex; exponent:Single ): fComplex;
function powReExpo( px:fPolar; exponent:Single ): fPolar;
fPolar principal( floag __mag, float __arg );
function principal( px:fPolar ): fPolar;
function quartic( zx:fComplex ): fComplex;
function quartic( px:fPolar ): fPolar;
float real( fComplex _z ); // to be used as zre = real ( _z );
function real( zx:fComplex ): Single;
function real( px:fPolar ): Single;
function reimtop( re, im:Single ): fPolar;
function sin( zx:fComplex ): fComplex;
function sinh( zx:fComplex ): fComplex;
function sqrt( zx:fComplex ): fComplex;
function sqrt( px:fPolar ): fPolar;
function square( zx:fComplex ): fComplex;
function square( px:fPolar ): fPolar;
function sub( zx:fComplex; yRe:Single ): fComplex;
function sub( yRe:Single; zx:fComplex ): fComplex;
function subRe( zx:fComplex; yRe:Single ): fComplex;
function subrRe( zx:fComplex; yRe:Single ): fComplex;
function tan( zx:fComplex ): fComplex;
function tanh( zx:fComplex ): fComplex;
Copyright for OptiVec and CMATH software and documentation
E N D
© 1996-2010 OptiCode - Dr. Martin Sander Software Dev.
All rights reserved!