OptiVec logo 

OptiVec
 
Version 8


für C/C++,  Delphi und Lazarus

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

Teil I.A: Handbuch

 

Dieses HANDBUCH beschreibt die Grundlagen der OptiVec-Bibliotheken und gibt einen Überblick über VectorLib, den ersten Teil von OptiVec. Das objekt-orientierte Interface VecObj wird in Kap. 3 beschrieben. Die übrigen Teile von OptiVec werden in separaten Dateien dokumentiert, siehe MATRIXD.HTM und CMATHD.HTM.
Kap. 1.2 der vorliegenden Datei enthält die Lizenz-Bedingungen der Shareware-Version, Kap. 1.3 diejenigen der registrierten Vollversion.
 
OptiCode™ und OptiVec™ sind Warenzeichen von Dr. Martin Sander Software-Entwicklung. Andere zum Zwecke der Identifikation hier erwähnte Warenzeichen sind Eigentum der jeweiligen Hersteller.
 

Inhaltsverzeichnis

1. Einführung
1.1 Warum sich vektorisierte Programmierung auf dem PC lohnt
 1.1.1 Allgemeine Optimierungs-Strategien von OptiVec
 1.1.2 Multi-Prozessor-Optimierung
 1.1.3 Unterstützung für CUDA-Hardware
 1.1.4 Auswahl der passenden OptiVec-Bibliothek
1.2 Lizenzbedingungen der Shareware-Version
1.3 Registrierte Vollversion
 1.3.1 Preise und Bestellmöglichkeiten
 1.3.2 Lizenzbedingungen
1.4 Installation und Start
1.5 Deklaration von OptiVec-Funktionen 1.6 Beispiel-Programme 2. Elemente von VectorLib-Funktionen
2.1 Synonyme für einige Datentypen
2.2 Komplexe Zahlen: Die Datentypen fComplex, dComplex, eComplex, fPolar, dPolar und ePolar
2.3 Vektoren und Arrays: Die Datentypen fVector, dVector, eVector, cfVector, pfVector, iVector, uVector usw.
2.4 Vektor-Funktionen reeller Zahlen: Die Präfixe VF_,  VD_ und VE_
2.5 Komplexe Funktionen: Die Präfixe VCF_,  VCD_,  VCE_,  VPF_,  VPD_ und VPE_
2.6 Funktionen der Ganzzahl-Datentypen: Die Präfixe VI_,  VBI_,  VSI_,  VU_ usw.
2.7 Gemeinsame Funktionen mehrerer Datentypen: Das Präfix V_
3. Nur C++: VecObj, das objekt-orientierte Interface für VectorLib
4. VectorLib-Funktionen: Ein kurzer Überblick
4.1 Erzeugung, Initialisierung und Freigabe von Vektoren
4.2 Index-orientierte Manipulationen
4.3 Datentyp-Umwandlungen
4.4 Nähere Informationen zur Ganzzahl-Arithmetik
4.5 Grundfunktionen komplexer Vektoren
4.6 Mathematische Funktionen
4.6.1 Rundung
4.6.2 Vergleiche
4.6.3 Direkte Bit-Manipulationen
4.6.4 Arithmetische Grundfunktionen, Akkumulation
4.6.5 Geometrische Vektor-Arithmetik
4.6.6 Potenzen
4.6.7 Exponential- und Hyperbel-Funktionen
4.6.8 Logarithmen
4.6.9 Trigonometrische Funktionen
4.7 Analysis
4.8 Signalverarbeitung: Fourier-Transformations-Techniken
4.9 Statistische Funktionen und Bausteine
4.10 Daten-Anpassung
4.11 Input und Output
4.12 Graphik
5. Fehlerbehandlung
5.1 Allgemeines
5.2 Ganzzahl-Fehler
5.3 Fließkomma-Fehler
5.4 Die Behandlung nicht-normalisierter Zahlen
5.5 Fortgeschrittene Fehlerbehandlung: Meldungen in eine Datei schreiben
5.6 OptiVec-Fehlermeldungen
6. Wenn etwas schiefgeht 7. Die Include-Dateien und Units von OptiVec

Teil I.B : Datei FUNKREF.HTM:
 
8. Funktions-Referenz VectorLib
9. Skalare (nicht-vektorisierte) Hilfsfunktionen


1. Einführung

OptiVec bietet eine umfangreiche Bibliothek zur effizienten und genauen Verarbeitung von Daten, die in ein- oder zweidimensionalen Arrays vorliegen. Das Konzept der "vektorisierten Programmierung" wird hiermit auf sehr einfache und übersichtliche Weise für die Sprachen C/C++ und Pascal/Delphi verfügbar gemacht. Der Ersatz konventioneller Schleifen durch Vektor- und Matrix-Funktionen führt zu einer starken Vereinfachung der Schreibarbeit des Programmierers und zu einem großen Gewinn an Geschwindigkeit und Genauigkeit der Programme.

Dem Ziel der Vereinfachung dienen zwar bereits seit mehr als zwei Jahrzehnten auch die Feldfunktionen von Fortran90 und templatisierte Vektor-Klassen in C++, doch sind dies lediglich Abkürzungen, die vom Compiler wieder in Schleifen übersetzt und entsprechend ineffizient verarbeitet werden. (Ähnliches gilt für die meisten der populären BLAS-Bibliotheken für Fortran). Demgegenüber bietet OptiVec eine hochoptimierte, in Assembler geschriebene Lösung, deren Geschwindigkeit nicht mehr durch die Qualität des Compilers, sondern nur noch durch die echte Geschwindigkeit des Prozessors bestimmt wird. Gegenüber compiliertem Code ergibt sich ein durchschnittlicher Geschwindigkeitsvorteil von einem Faktor 2 bis 3 (für einige Funktionen auch bis zu 8).

Nach unserem Kenntnisstand war OptiVec beim Erscheinen 1996 die erste umfassende Vektor- und Matrix-Bibliothek für PC-Compiler, die praktisch vollständig in Maschinensprache geschrieben wurde.

OptiVec tritt in Konkurrenz zu etlichen teuren integrierten Programmsystemen für wissenschaftliche und Datenverarbeitungs-Anwendungen, ist aber eben nicht ein "geschlossenes" integriertes Paket, sondern zur Verwendung mit den gängigen Programmiersprachen bestimmt, wodurch dem OptiVec-Benutzer die Flexibilität seiner bevorzugten Programmierumgebung erhalten bleibt.

Hier einige Stichworte:

Der große Funktions-Umfang, die hohe numerische Genauigkeit und die Einfachkeit der Benutzung machen OptiVec zu einem wertvollen Programmierwerkzeug für wissenschaftlich-technische Datenverarbeitungs-Anwendungen.

Die vorliegende Dokumentation beschreibt die Implementierungen von OptiVec für

Man beachte, dass nur die Dokumentation für diese verschiedenen Compiler gemeinsam gültig ist. Die Bibliotheken selbst sind Compiler-spezifisch; jede von ihnen kann nur mit einem dieser Compiler und – im Falle von C/C++ – mit jeweils einer bestimmten Target-Konfiguration verwendet werden.
  1. Shareware-Versionen
    Es ist nur eine Auswahl an Bibliotheken enthalten:
    1. 64-bit: P8D (Allzweck-Debug-Version, kompatibel bis hinab zu Core2 und AMD64) und
      P9M (Automatisches Multi-Threading, verlangt aktuelle Prozessoren ab Intel Haswell oder AMD Excavator).
    2. 32-bit: P4D (Allzweck-Debug-Version für größtmögliche Prozessor-Kompatibilität bis hinab zu 486DX / Pentium / Athlon).
      Diese Version läuft auf allen 32-bit-Windows-Betriebssystemen sowie im 32-bit-Modus von 64-bit-Windows.
    3. 32-bit Multi-Prozessor-Bibliothek für den Einsatz auf AMD64 x2, Core2 Duo oder deren Mehrkern-Nachfolgern. Außer der durch automatische Verteilung der Rechenlast auf die vorhandenen Prozessorkerne (Auto-Threading) bewirkten Effizienz-Steigerung wird noch zusätzlich durch Einsatz der sog. SSE- und SSE2-Befehle eine Geschwindigkeitssteigerung vieler Fließkomma-Operationen erzielt. Außer Bereichs-Fehlern (DOMAIN) werden alle anderen mathematischen Fehler (Überlauf, Singularität, Genauigkeits-Verlust) ohne Meldung "stillschweigend" durch Setzen des für jede Funktion angegebenen Standardwertes abgefangen.
  2. Vollversionen
    Die Bibliotheken sind in vier Prozessor-Versionen enthalten: Diese Versionen sind nochmals unterteilt:

Besonderheiten der Versionen für die einzelnen Compiler

Einzelheiten werden in Kap. 1.4 im Zusammenhang mit der Auswahl der einzubindenden Bibliotheken besprochen. Hier daher nur in Kürze:

Zurück zum Inhaltsverzeichnis

1.1 Warum sich vektorisierte Programmierung auf dem PC lohnt

Um eindimensionale Datenfelder oder "Vektoren" zu verarbeiten, schreibt der Programmierer normalerweise eine Schleife über alle Vektor-Elemente. Und zwei- oder höher-dimensionale Felder ("Matrizen" oder "Tensoren") werden üblicherweise mittels verschachtelter Schleifen über die Indizes in allen Dimensionen verarbeitet. Die Alternative zu diesem klassischen Programmier-Stil sind Vektor- und Matrix-Funktionen.
Vektor-Funktionen wirken auf ganze Vektoren anstatt einzelne skalare Argumente. Sie stellen die konsequenteste Form der "Vektorisierung" dar, also der Organisation von Programm-Code (sei es durch optimierende Compiler oder durch den Programmierer selbst) mit dem Ziel der Optimierung der Behandlung von Vektoren.

Vektorisierung war schon immer die Zauberformel für Supercomputer mit ihren aus vielen einzelnen Prozessoren gebildeten Parallel-Architekturen. Auf diesen Architekturen wird versucht, die Rechenlast möglichst gleichmäßig auf alle Prozessoren zu verteilen und so die Ausführungsgeschwindigkeit zu maximieren. Die sogenanten "divide and conquer"-Algorithmen spalten kompliziertere numerische Aufgaben in kleine Schleifen über Vektorelemente auf. Hochgezüchtete Compiler finden dann den effizientesten Weg für die Verteilung der Vektor-Elemente auf die Prozessoren. Viele Compiler für Supercomputer enthalten bereits große Bibliotheken vordefinierter Vektor- und Matrixfunktionen für viele Anwendungszwecke. Diese Vektor- und Matrixfunktionen bieten den besten Weg, maximalen Datendurchsatz zu erzielen.

Es ist offensichtlich, daß die massive Parallelverarbeitung einer Cray auf den meisten PCs mit ihren eher bescheidenen 2, 4 oder allenfalls 8 Prozessor-Kernen nicht in gleicher Weise möglich ist. Auf den ersten Blick mag es daher sinnlos erscheinen, das Konzept der vektorisierten Programmierung auch auf dem PC anzuwenden. Tatsächlich aber sind auch viele vektor-spezifische Optimierungen möglich, selbst wenn nur eine CPU vorhanden ist. Viele dieser Optimierungen können von heutigen Compilern nicht direkt durchgeführt werden. Stattdessen muß der Programmierer auf Maschinensprachen-Niveau heruntergehen. Hand-optimierte, in Maschinensprache geschriebene Vektorfunktionen übertreffen compilierte Schleifen in der Geschwindigkeit durchschnittlich um einen Faktor von 2-3. Dies bedeutet, daß Vektorisierung die Mühe sehr wohl lohnen kann, auch für PC-Programme.

1.1.1 Allgemeine Optimierungs-Strategien von OptiVec

Hier sind die wichtigsten Optimierungs-Strategien, die in OptiVec zur Steigerung der Performance auf eingesetzt werden – unabhängig von der Zahl der Prozessor-Kerne:

Preload von Konstanten
Anstatt Konstanten für jeden einzelnen Funktionsaufruf innerhalb einer Schleife neu zu laden und wieder zu entladen, werden sie nur einmalig zu Beginn einer Vektor-Funktion geladen und stehen für die Verarbeitung sämtlicher Vektor-Elemente zur Verfügung.

Volle XMM- und FPU-AusnutzungWo immer nötig und sinnvoll, werden alle acht XMM-Register (in der 64-bit-Version sogar sechzehn) bzw. alle acht Coprozessor-Register eingesetzt (für einen Compiler ist es schon eine hervorragende Leistung, die Buchführung für vier Coprozessor-Register zu beherrschen).

Prefetch von Gruppen von Vektor-Elementen
Ab dem Pentium III stehen sehr nützliche "Prefetch"-Befehle zur Verfügung, die es erlauben, Daten schon genügend im voraus aus dem Hauptspeicher in den Prozessor zu laden, so daß sie gleich zur Verfügung stehen, wenn sie verarbeitet werden sollen.

Verwendung von SIMD-Befehlen
Man mag sich wundern, warum diese Strategie nicht gleich an erster Stelle genannt ist. Seit Einführung der SSE oder "Streaming Single-Instruction-Multiple-Data Extensions" mit dem Pentium III und zahlreichen Verbesserungen und Erweiterungen in jeder neuen Prozessor-Generation ist hier explizite Unterstützung für Vektor-Programmierung gegeben. Auf den ersten Blick sollten sie also die Vektor-Programmierung auf dem PC geradezu revolutionieren. Angesichts einer immer noch vorhandenen Diskrepanz zwischen Prozessor- und Datenbus-Geschwindigkeit sind aber viele der einfachen arithmetischen Operationen in ihrer Geschwindigkeit durch den Datenfluß begrenzt. Hier können SIMD-Befehle nur noch zu einem geringeren Geschwindigkeitsvorteil führen, als man eigentlich erwarten würde. Für kompliziertere Operationen wiederum können SIMD-Befehle oft gar nicht verwendet werden, wenn nämlich entweder bedingte Verzweigungen für jedes Vektor-Element individuell erforderlich sind, oder auch dann, wenn ohne die interne extended-Genauigkeit der FPU umständlichere Algorithmen gewählt werden müßten. OptiVec macht daher von den SSE-Befehlen überall dort Gebrauch, wo ein wirklicher Geschwindigkeitsvorteil erzielt werden kann. Man beachte allerdings, dass Operationen wie Matrix-Multiplikation oder Fourier-Transformation in float-Präzision zugunsten des hier möglichen erheblichen Geschwindigkeitsgewinnes einen Genauigkeitsverlust von 1-2 Stellen in Kauf nehmen. Wer demgegenüber auf maximale Genauigkeit Wert legen muss, sollte daher stets die ausschließlich FPU-Befehle verwendende P4-Version einsetzen.

Superscalar schedulingDurch sorgfältige Anordnung der Befehls-Folge können die parallelen Integer-Pipes und fadd/fmul-Einheiten moderner Prozessoren (seit Pentium) bestmöglich ausgenutzt werden.

Loop-unrolling
Auch dort, wo SIMD-Befehle nicht angewandt werden können oder wo eine optimale Ausnutzung der parallelen Prozessor-Pipes nicht für einzelne Vektor-Elemente erzielt werden kann, werden die Vektor-Elemente oft zu zweit, zu viert oder noch mehreren verarbeitet. Hierdurch werden einerseits die parallelen Pipes beschäftigt, andererseits auch der relative Anteil des Schleifen-Managements an der gesamten Ausführungszeit zurückgedrängt. Im Zusammenhang mit den oben beschriebenen "Prefetch"-Mechanismen wird die Schleifengröße möglichst an die Cache-Zeilengröße angepaßt.

Vereinfachte Adressierung
Die Adressierung von Vektor- und erst recht von Matrix-Elementen stellt noch immer eine Hauptquelle für ineffizienten Code heutiger Compiler dar. Durch Hin- und Herschaltung zwischen Eingabe- und Ausgabe-Vektoren wird eine große Zahl redundanter Adressierungs-Operationen ausgeführt. Durch die ebenso strikte wie einfache Definition "Verarbeitung von hier bis da" können die OptiVec-Funktionen den Aufwand für die Adressierung von Array-Elementen auf das nötige Minimum reduzieren.

Ersatz von Fließkomma- durch Ganzzahl-Befehle
Eine Reihe von Fließkomma-Operationen (wie Kopieren, Austauschen, Vergleich mit Sollwerten) kann wahlweise mit Ganzzahl- oder Fließkomma-Prozessorbefehlen implementiert werden. Hier wird natürlich die jeweils schnellste Methode angewandt.

Strikte Genauigkeits-Kontrolle
C/C++-Compiler wandeln eine float-Zahl oft in double um – 32-bit-Pascal/Delphi sogar in extended – bevor sie an eine mathematische Funktion übergeben wird. Diese Behandlung war einmal sinnvoll, als Festplattenspeicher zu teuer war, um in den .LIB-Dateien separate Funktionen für alle Datentypen einzuschließen. Auf heutigen PCs ist sie schlicht ineffizient. Konsequenterweise werden in den OptiVec-Routinen keine solchen impliziten Umwandlungen durchgeführt. Hier wird eine float-Funktion auch nur in float- (also einfacher) Genauigkeit berechnet, unter Verzicht auf die soundsovielte Stelle nach dem Komma, die ohnehin sofort wieder abgeschnitten wird. Zusätzlich kann V_setFPAccuracy( 1 ); aufgerufen werden, um die FPU auf einfache Genauigkeit umzuschalten, falls man sich generell mit dieser begnügen möchte. Hierdurch kann die Ausführungsgeschwindigkeit etwas gesteigert werden. Seien Sie aber darauf gefasst, dass die Genauigkeit Ihrer Endergebnisse noch deutlich unter der float-Spezifikation liegen kann, wenn schon die Zwischenergebnisse nur einfach-genau berechnet werden. Details werden bei V_setFPAccuracy aufgeführt.

Inline-Coding
Alle externen Funktionsaufrufe sind aus den Schleifen eliminiert. Dadurch wird die Ausführungszeit der "call / ret"-Paare sowie die Zeit für die Übergabe der Funktionsargumente eingespart.

Cache-line-Matching lokaler Variablen
Der Level−1-Cache aktueller Prozessoren ist in Zeilen von je 64 Byte organisiert (bei den Vorgängern waren es 32 Byte). Viele OptiVec-Funktionen benötigen doppelt- oder extended-genaue Variablen auf dem Stack (vor allem für Ganzzahl/Fließkomma-Umwandlungen oder für Bereichsprüfungen). 32-bit-Compiler und -Linker richten den Stack an 4-Byte-Grenzen aus. Es besteht also die Gefahr, dass die 8 Bytes einer double oder die 10 bytes einer extended beim Speichern auf dem Stack eine 64-Byte-Grenze überschreiten. Dies wiederum würde zu starken Geschwindigkeits-Einbußen durch Cache-Zeilenumbrüche führen. Um diese zu vermeiden, richten alle OptiVec-Funktionen, für die dies eine Rolle spielt, ihre lokalen Variablen an 8-Byte- (für double), 16-Byte- (für extended) bzw. 64-Byte-Grenzen aus (XMM- und YMM-Werte).

Ungeschützte und bereichsreduzierte Funktionen
OptiVec bietet alternative Formen einiger mathematischer Funktionen, bei denen man zwischen der geschützten Variante mit Fehlerbehandlung und einer ungeschützten Variante ohne Fehlerdetektion währen kann. In einigen Funktionen, die ganzzahlige Potenzen ausrechnen, erlaubt die Abwesenheit der Fehlerdetektion eine viel effizientere Codierung. Ähnliches gilt für die Sinus- und Cosinus-Funktion für mit Sicherheit zwischen -2p und +2p liegenden Argumenten. In diesen Spezialfällen kann die Ausführungszeit um bis zu 40% reduziert werden, abhängig von der Hardware-Umgebung. Dieser Geschwindigkeitsgewinn wird allerdings durch erhöhtes Risiko erkauft: Falls auch nur ein einziges Vektorelement außerhalb des gültigen Bereiches liegt, stürzen die ungeschützten und bereichsreduzierten Funktionen ohne Warnung einfach ab.

1.1.2 Multi-Prozessor-Optimierung

Multithread Support
Moderne Betriebssysteme erlauben es, innerhalb eines Programmes parallel laufende Threads auf die vorhandenen Prozessorkerne zu verteilen so die Performance gegenüber Single-Thread-Verarbeitung zu vervielfachen. Hierfür muß aber sichergestellt sein, daß in parallelen Threads laufende Funktionen sich nicht gegenseitig ihre Zwischenergebnisse überschreiben. Mit sehr wenigen Ausnahmen (namentlich den Plotting-Funktionen) sind alle übrigen OptiVec-Funktionen re-entrant, also darauf ausgerichtet, parallel zueinander laufen zu können.

Bei der Entwicklung Ihrer Multi-Thread-Anwendung stehen Ihnen zwei grundsätzlich verschiedene Optionen zur Verfügung: Funktionale Parallelität und Daten-Parallelität.

Funktionelle Parallelität
Verschiedene Threads führen verschiedene Aufgaben aus – sie unterscheiden sich in ihrer Funktion. Als Beispiel denke man an eine Anwendung, bei der ein Thread Benutzer-Ein- und Ausgaben abarbeitet, während ein anderer Thread Hintergrund-Berechnungen durchführt. Selbst auf einer Ein-Kern-CPU kann diese Art des Multi-Threading durch die vom Betriebssystem bewirkte ständige Umschaltung zwischen den beiden Threads Vorteile bieten (z.B., dass das Benutzer-Interface nicht blockiert, während die Hintergrundberechnungen ausgeführt werden, sondern weiterhin Eingaben annehmen kann). Auf einem Mehr-Prozessor-Computer können die zwei (oder mehr) Threads tatsächlich gleichzeitig auf den verschiedenen Prozessor-Kernen laufen. Normalerweise ist die Lastverteilung zwischen den Prozessoren bei funktionellem Multi-Threading alles andere als perfekt: Oft läuft ein Prozessor unter Volllast, während ein anderer arbeitslos auf Eingaben wartet. Dennoch ist diese Art des Multi-Threading die beste Option für Anwendungen, die nur kleine bis mittelgroße Vektoren und Matrizen umfassen.

Daten-Parallelität
Um die Lastverteilung zwischen den vorhandenen Prozessor-Kernen zu verbessern und so den Datendurchsatz zu maximieren, kann die klassische Parallelverarbeitung angewandt werden: Die Daten-Vektoren und -Matrizen werden in kleinere Teile zerlegt, und jeder Thread arbeitet einen solchen Teil ab. Die Brauchbarkeit dieses Ansatzes wird dadurch beschränkt, dass der Aufwand für die Verteilung der Daten auf die verschiedenen Threads und für die dabei nötige Kommunikation der Threads untereinander ziemlich hoch ist. Außerdem lassen sich die Daten niemals vollständig parallelisieren; es verbleibt immer ein gewisser Teil der Aufgaben, der nur sequentiell abgearbeitet werden kann. Daher lohnt sich Daten-Parallelität nur für größere Vektoren und Matrizen. Typische Schwellen-Größen, ab denen die Leistung mehrerer Prozessoren den für die Verteilung auf sie nötigen Aufwand "zurückverdient", reichen von unter 100 (bei mathematischen Funktionen komplex-zahliger Vektoren) bis zu über 10.000 Elementen (bei den einfachen arithmetischen Funktionen). Erst wenn die Vektoren / Matrizen deutlich größer als diese Schwellenwerte sind, kommt die erhöhte Leistung voll zum Tragen. Dann erst nähert sich die Beschleunigung dem theoretischen Grenzwert einer Verdopplung, Vervierfachung usw. an.

1.1.3 Unterstützung für CUDA-Hardware

Moderne Graphik-Karten sind mit bis zu mehreren hundert Prozessorkernen bestückt, die alle parallel laufen können. In den letzten Jahren wurden Interfaces entwickelt, die es erlauben, diese geballte Rechenpower außer für Graphik- auch für allgemeine Berechnungen nutzbar zu machen. Einer dieser Ansätze ist das CUDA-Konzept von NVIDIA. Alle aktuellen NVIDIA-Graphikkarten unterstützen CUDA. Außerdem bietet NVIDIA spezielle Hochleistungs-Hardware an, die von vornherein nicht als Graphikkarten, sondern als Vektor-Coprozessor gedacht ist. Mit den cudaOptiVec-Bibliotheken (gekennzeichnet durch ein "C" im Namen, z.B. OVVC8C.LIB oder OVBC64_8C.a) bietet OptiVec einen einfachen Weg, um CUDA-Hardware für Vektor-/Matrix-Berechnungen zu nutzen - ohne die Schwierigkeiten tatsächlicher CUDA-Programmierung. Es gibt einige Punkte zu beachten:

1.1.4 Auswahl der passenden OptiVec-Bibliothek

Wenn Ihre Anwendung auf einem breiten Spektrum unterstützter Prozessoren laufen sollen und wenn Ihre Vektoren / Matrizen nur von kleiner bis mittlerer Größe sind (wenige 100 bis wenige 1000 Elemente, je nach Art der durchgeführten Berechnungen), empfehlen wir unter 32-bit die P4- Allzweck-Bibliotheken (z.B. OVVC4.LIB  für MS Visual C++),  VCF4W.LIB  für Embarcadero/Borland C++), unter 64-bit die P8-Allzweck-Bibliotheken. Sie verbinden gute Performance mit Rück-Kompatibilität zu älterer Hardware bis hinab zu 486DX, Pentium und den frühen Modellen des Athlon. Sie alle sind Thread-sicher und unterstützen funktionelle Parallelität. Falls Sie nicht die volle Fließkomma-Genauigkeit und auch nicht dieses Ausmaß an Rückwärts-Kompatibilität benötigen, können Sie höhere Leistungen erzielen durch den Einsatz der P8-Bibliotheken für Core2xxx / AMD64xxx mit SSE3 (gekennzeichnet durch die Ziffer "8") oder die P9-Bibliotheken (ab Intel "Haswell", AMD "Steamroller" mit AVX und AVX2).

Für mittlere bis große Vektoren und Matrizen auf Mehrkern-Rechnern bietet sich die Verwendung der multi-core-optimierten Bibliotheken an. Diese verteilen für jede einzelne Funktion die Arbeitslast über die vorhandenen Prozessor-Kerne (Auto-Threading). Sie werden durch den Buchstaben "M" gekennzeichnet, also z.B. OVVC8M.LIB  ,  ovgc64_9m.lib, etc. Diese Bibliotheken sind für Multiprozessor-Computer wie AMD64 X2, Intel i5, Core2Duo oder Workstations mit mehreren Prozessoren gedacht.
Die CUDA-Bibliotheks-Versionen basieren auf den "M"-Bibliotheken und lagern die Verarbeitung nur für sehr große Vektoren auf die Graphik-Karte aus. Sie sind durch den Buchstaben "C" markiert, z.B.  OVBC64_8C.LIB.
Die "M"- und "C"- Bibliotheken laufen immer noch auf Ein-Kern-Computern. Durch die "Bürokratie-Verluste" beim Thread-Management sind sie hier aber deutlich langsamer als die Allzweck-Bibliotheken. Obwohl die "M"-Bibliotheken im Hinblick auf mittlere bis größere Vektoren entwickelt wurden, sind die Einbußen bei Verwendung mit kleinen Vektoren nicht sehr hoch, da die OptiVec Thread-Engine eine Funktion automatisch in einem einzelnen Thread ausführt, wenn die Vektor-Größe nicht ausreicht, um den Verteilungs-Aufwand durch die Parallel-Ausführung (oder gar durch die Auslagerung auf den Graphik-Prozessor) wieder aufzuholen.
Wenn Sie die "M"- oder "C"-Bibliotheken verwenden, muss Ihr Programm zu Beginn V_initMT( nVorhandeneProzKerne ) aufrufen.

Zurück zum Inhaltsverzeichnis

Die folgenden Lizenzbedingungen gelten für die Shareware-Version von OptiVec. Die Lizenzbedingungen für die registrierte Vollversion finden Sie in Kap. 1.3. Dies ist die Shareware-Version von OptiVec ("SOFTWARE").
Ihre Nutzung unterliegt den folgenden Lizenzbedingungen:

  1. Sie dürfen diese SOFTWARE gebührenfrei für einen Zeitraum von 90 Tagen auf einem Rechner testen.
  2. Sonderbedingung für die 32-bit P4D und die 64-bit P8D Bibliotheken für GCC und für LLVM CLang: Diese Bibliotheken sind Freeware. Sie dürfen kostenfrei und zeitlich unbegrenzt genutzt werden, sowohl in nicht-kommerziellen als auch in kommerziellen Anwendungen. Mit diesen Bibliotheken erstellte Anwendungen dürfen unbegrenzt an Dritte weitergegeben werden.
  3. Mit der Shareware-Version dieser SOFTWARE erstellte Anwendungen sind nur auf demselben Rechner lauffähig, auf dem die SOFTWARE installiert wurde. Sie können und dürfen nicht an Dritte weitergegeben werden. Nach dem Ende der Test-Zeit sind sie nicht mehr ausführbar.
  4. Falls Sie die SOFTWARE nach Ablauf der Testzeit weiterbenutzen und/oder Anwendungen, die Funktionen dieser SOFTWARE enthalten, zu gewerblichen Zwecken verwenden möchten, müssen Sie die registrierte Vollversion erwerben (siehe Kap. 1.3).
  5. Die SOFTWARE wird auf "as is"-Basis zur Verfügung gestellt. Jegliche explizite oder implizite Garantieleistungen sind ausdrücklich ausgeschlossen.
  6. Trotz sorgfältigen Testens können keinerlei Zusicherungen bezüglich des fehlerfreien Funktionierens, der Eignung für einen bestimmten Zweck oder der Marktgängigkeit gemacht werden.
  7. Daher darf diese SOFTWARE nicht in Umgebungen oder unter Umständen eingesetzt werden, unter denen Fehler der SOFTWARE zu größeren materiellen Verlusten oder gar zu Schäden an Leib und Leben führen könnten.
  8. Zurück-Entwickeln (Reverse engineering), Dekompilieren und Entassemblieren der SOFTWARE sind nicht gestattet. Selbstverständlich dürfen Sie aber die in Ihre eigenen Programme eingebundenen Funktionen der SOFTWARE mit Hilfe von Debuggern (wie z.B. den mit den Compilern von Borland oder Microsoft gelieferten) inspizieren.
Copyright für SOFTWARE und Dokumentation © 1996-2024 OptiCode –Dr. Martin Sander Software-Entwicklung.
Alle Rechte vorbehalten.

Zurück zum Inhaltsverzeichnis

1.3 Registrierte Vollversion

1.3.1 Preise und Bestellmöglichkeiten

Sie können entweder eine Lizenz für die jeweils für einen einzigen Target-Compiler geeigneten Bibliotheken erwerben ("OptiVec / CMATH for xxx") oder für einen geringen Aufpreis eine OptiVec / CMATH Master-Lizenz, die sämtliche unterstützten Compiler abdeckt.
Um dieses Produkt auch für diejenigen erschwinglich zu machen, die durch seinen Einsatz selbst kein Geld verdienen, bieten wir zusätzlich zur kommerziellen Edition auch eine Schulversion zu einem stark reduzierten Preis an. Inhaltlich sind beide Versionen identisch. Sie unterscheiden sich lediglich in den Nutzungs-Beschränkungen der Schulversion, die nicht für kommerzielle Zwecke und nicht in nicht-bildungsbezogenen staatlichen Institutionen eingesetzt werden darf.
Der Erwerb der registrierten Version gibt Ihnen das Recht der Verwendung auf so vielen Rechnern gleichzeitig wie Sie Lizenzen erworben haben.
Das Recht, OptiVec-Funktionen enthaltende Anwendungen an Dritte weiterzugeben, ist in der kommerziellen Edition enthalten. Es sind keine zusätzlichen Laufzeit-Lizenzen für Ihre Kunden erforderlich. Großkunden-Lizenzen sind auf Anfrage erhältlich!

Preisliste

 
OptiVec für einzene Compiler:
C++ Builder,    Visual C++,   GCC (Win),   LLVM CLang (Win),   Delphi,   Lazarus / FreePascal    oder Linux (GCC / CLang)
  Preise incl. 19% deutscher MWStPreise netto
kommerzielle Edition 
Einzel-Lizenz
 5-fach Lizenz
10-fach Lizenz
EUR   199
EUR   595 (119,00 pro Lizenz)
EUR   995 ( 99,50 pro Lizenz)
EUR   167,23
EUR   500,00 (100,00 pro Lizenz)
EUR   836,13 ( 83,61 pro Lizenz)
Schulversion
Einzel-Lizenz
 5-fach Lizenz
10-fach Lizenz
EUR    99
EUR   269 ( 53,80 pro Lizenz)
EUR   499 ( 49,90 pro Lizenz)
EUR    83,19
EUR   226,05 ( 45,21 pro Lizenz)
EUR   419,33 ( 41,93 pro Lizenz)
 
OptiVec Master-Lizenz für alle unterstützten Compiler
  Preise incl. 19% deutscher MWStPreise netto
kommerzielle Edition 
Einzel-Lizenz
 5-fach Lizenz
10-fach Lizenz
EUR   299
EUR   899 (179,80 pro Lizenz)
EUR  1499 ( 149,90 pro Lizenz)
EUR   251,26
EUR   755,46 (151,09 pro Lizenz)
EUR  1259,66 (125,97 pro Lizenz)
Schulversion
Einzel-Lizenz
 5-fach Lizenz
10-fach Lizenz
EUR   149
EUR   445  (89,00 pro Lizenz)
EUR   745  (74,50 pro Lizenz)
EUR   125,21
EUR   373,95  (74,79 pro Lizenz)
EUR   626,05  (62,61 pro Lizenz)
 
CMATH separat; für einzene Compiler:
C++ Builder,    Visual C++,   GCC (Win),   LLVM CLang (Win),   Delphi,   Lazarus / FreePascal    oder Linux (GCC / CLang)
  Preise incl. 19% deutscher MWStPreise netto
kommerzielle Edition 
Einzel-Lizenz
 5-fach Lizenz
10-fach Lizenz
EUR    59
EUR   175  (35,00 pro Lizenz)
EUR   295  (29,50 pro Lizenz)
EUR    49,58
EUR   147,06  (29,41 pro Lizenz)
EUR   247,90  (24,79 pro Lizenz)
Schulversion
Einzel-Lizenz
 5-fach Lizenz
10-fach Lizenz
EUR    29
EUR    85  (17,00 pro Lizenz)
EUR   145  (14,50 pro Lizenz)
EUR    24,37
EUR    71,43  (14,29 pro Lizenz)
EUR   121,85  (12,19 pro Lizenz)
 
CMATH separat; Master-Lizenz für alle unterstützten Compiler
  Preise incl. 19% deutscher MWStPreise netto
kommerzielle Edition 
Einzel-Lizenz
 5-fach Lizenz
10-fach Lizenz
EUR    89
EUR   265  (53,00 pro Lizenz)
EUR   445  (44,50 pro Lizenz)
EUR    74,79
EUR   222,69  (44,54 pro Lizenz)
EUR   373,95  (37,40 pro Lizenz)
Schulversion
Einzel-Lizenz
 5-fach Lizenz
10-fach Lizenz
EUR    49
EUR   145  (29,00 pro Lizenz)
EUR   245  (24,50 pro Lizenz)
EUR   41,18
EUR   121,85  (24,37 pro Lizenz)
EUR   205,88  (20,59 pro Lizenz)

Bei postalischer Lieferung (CD-ROM) zzgl. EUR 5,- Versandkosten-Pauschale.

Die Preise incl. deutscher MWSt gelten innerhalb Deutschlands sowie für private Besteller innerhalb der EU. Falls Sie eine Europäische VAT ID besitzen oder von außerhalb der Europäischen Union bestellen, entfällt die deutsche MWSt. Dafür muß vom Erwerber der in seinem Heimatland gültige Satz abgeführt werden, bei Lieferung außerhalb der EU gegebenenfalls auch noch Import-Zoll.

Bestellungen bitte über www.optivec.de/order/ oder mit diesem Bestell-Formular an

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

Zurück zum Inhaltsverzeichnis

1.3.2 Lizenzbedingungen für die registrierte Vollversion


 
Dies ist eine Einzelplatz-Lizenz für OptiVec ("SOFTWARE"), die Ihnen als End-Anwender von OptiCode –Dr. Martin Sander Software-Entwicklung ("OptiCode") gewährt wird. Der Begriff "Anwender" bezeichnet einen Programmierer, der Binär-Code dieser SOFTWARE in von ihm geschriebene Anwendungen einbindet. Diejenigen wiederum, die seine Anwendungen benutzen, ohne dafür diese SOFTWARE selbst installieren zu müssen, benötigen keine eigene Laufzeit-Lizenz für die SOFTWARE. Das Recht, Anwendungen kommerziell zu nutzen und weiterzugeben, ist in der Lizenzgebühr der kommerziellen Version enthalten.

Nach Zahlung der im Kaufpreis enthaltenen Lizenzgebühr dürfen Sie die SOFTWARE für unbegrenzte Zeit benutzen, sofern Sie das Copyright nicht verletzen und die folgenden Regeln einhalten:

  1. Die SOFTWARE darf auf jedem hierfür geeigneten Computer verwandt werden, solange nicht mehr als eine Person sie gleichzeitig benutzt. Wenn mehrere Personen die SOFTWARE auf einem oder mehreren Computern gleichzeitig benutzen wollen (z.B. in einem Netzwerk), ist eine Mehrfach-Lizenz zu erwerben.
  2. Sie dürfen zum persönlichen Gebrauch Backup-Kopien der gelieferten Datenträger machen. Sie dürfen die SOFTWARE nicht verleihen oder vermieten. Sie dürfen sie jedoch auf Dauer an einen anderen übertragen, sofern Sie die Original-Datenträger vollständig weitergeben und alle von Ihnen gemachten Kopien vernichten und sofern sich der Empfänger mit diesen Lizenzbedingungen einverstanden erklärt.
  3. Zurück-Entwickeln (Reverse engineering), Dekompilieren und Entassemblieren der SOFTWARE sind nicht gestattet. Selbstverständlich dürfen Sie aber die in Ihre eigenen Programme eingebundenen Funktionen der SOFTWARE mit Hilfe von Debuggern (wie z.B. den mit den Compilern von Borland oder Microsoft gelieferten) inspizieren.
  4. Falls Sie die ermäßigte Lizenzgebühr für die Schulversion anstelle der vollen Gebühr für die kommerzielle Version der SOFTWARE in Anspruch genommen haben, ist der Einsatz der SOFTWARE auf private Nutzung sowie Nutzung zum Zwecke der Ausbildung beschränkt. In diesem Falle darf die SOFTWARE nicht für kommerzielle Zwecke und nicht für andere staatliche Aufgaben als Erziehung und Ausbildung eingesetzt werden.
    Anwendungen, die Funktionen dieser SOFTWARE verwenden, dürfen nur dann gebührenfrei weitergegeben werden (ohne Laufzeit-Lizenz), wenn sie mit der kommerziellen Version erstellt wurden. Außerdem müssen die Funktionen der SOFTWARE permanent in die jeweilige Anwendung eingebunden sein und dürfen dem Benutzer der Anwendung nicht als Bibliothek entgegentreten.
  5. Die SOFTWARE darf nicht in Umgebungen oder unter Umständen eingesetzt werden, unter denen eventuelle Fehler der SOFTWARE zu einer Gefahr für irgendjemandes Leib und Leben oder zu größeren materiellen Verlusten führen könnten.
  6. Die Haftung von OptiCode ist durch die beigefügte Beschränkte Garantie eingeschränkt. In jedem Fall ist die Haftung von OptiCode auf den Betrag beschränkt, den Sie tatsächlich für die Benutzung der SOFTWARE bezahlt haben.

Beschränkte Garantie für die registrierte Vollversion
  1. OptiCode garantiert, daß die magnetischen oder optischen Medien, auf denen die SOFTWARE aufgezeichnet ist, sowie die gedruckte Dokumentation bei normaler Benutzung frei von Material- und Verarbeitungsfehlern sind. Ferner wird garantiert, daß die SOFTWARE selbst im Wesentlichen gemäß der begleitenden gedruckten Dokumentation arbeitet.
  2. Die obigen Garantien gelten für einen Zeitraum von sechs Monaten ab Empfangsdatum.
  3. Die gesamte Haftung von OptiCode und Ihr alleiniger Anspruch als Kunde besteht nach Wahl von OptiCode entweder in der Rückerstattung des bezahlten Preises oder in dem Ersatz der obiger Garantie nicht genügenden und an OptiCode (unter Nachweis des rechtmäßigen Erwerbs) zurückgegebenen Teile.
  4. Trotz sorgfältigen Testens kann nicht garantiert werden, daß die SOFTWARE oder die Dokumentation vollständig frei von Fehlern sind.
  5. Alle impliziten Garantien, z.B. bezüglich Marktgängigkeit oder Eignung für einen bestimmten Zweck, sind auf die oben explizit gegebenen Garantien beschränkt.
  6. OptiCode ist nicht für Folgeschäden (uneingeschränkt eingeschlossen sind Schäden aus entgangenem Gewinn, Betriebsunterbrechung, Verlust von geschäftlichen Informationen oder Daten oder aus anderem finanziellen Verlust) ersatzpflichtig, die aufgrund der Benutzung dieses Produktes oder der Unfähigkeit, es zu verwenden, entstehen, selbst wenn OptiCode von der Möglichkeit eines solchen Schadens unterrichtet worden ist. Dieser Ausschluß gilt nicht für Schäden, die durch Vorsatz oder grobe Fahrlässigkeit auf seiten von OptiCode verursacht wurden. Ansprüche, die auf unabdingbaren gesetzlichen Vorschriften zur Produkthaftung beruhen, bleiben ebenfalls unberührt.

Copyright für SOFTWARE und Dokumentation
© 1996-2024 OptiCode –Dr. Martin Sander Software-Entwicklung. Alle Rechte vorbehalten.

Zurück zum Inhaltsverzeichnis

1.4 Installation und Start

Sie benötigen zunächst eine bereits installierte Kopie Ihres Compilers. Installieren Sie dann OptiVec, indem Sie INSTALL.EXE ausführen. Normalerweise wird OptiVec in ein Verzeichnis mit dem Namen "OPTIVEC" installiert. Es steht Ihnen jedoch frei, ein anderes Verzeichnis zu wählen. Dieses Verzeichnis enthält nach abgeschlossener Installation die Dokumentation.
Sie werden dieses Verzeichnis dem Bibliotheks-Suchpfad und dem Include-File-Suchpfad (C/C++) bzw. dem Units-Suchpfad (Pascal/Delphi) hinzufügen.
Springen Sie zur Beschreibung für Ihre spezifische Version:
 OptiVec für C++ Builder (Embarcadero / Borland C++)
OptiVec für Visual C++
OptiVec für GCC
OptiVec für LLVM CLang
OptiVec für Delphi
OptiVec für Lazarus / FreePascal

1.4.1 OptiVec für C++ Builder (Embarcadero / Borland C++)


Angenommen, Ihr OptiVec-Verzeichnis sei C:\OPTIVEC, müssen Sie
C:\OPTIVEC\LIB zu dem Bibliotheks-Suchpfad und
C:\OPTIVEC\INCLUDE zu dem Suchpfad für Include-Dateien hinzufügen. Beides sollte sowohl in der IDE (Options/Directories) also auch – falls Sie ihn verwenden – in den Konfigurationsdateien des Kommandozeilen-Compilers, BCC32.CFG, geschehen.
 

Sie müssen nicht nur eine, sondern zwei OptiVec-Bibliotheken einschließen. Die erste, die "Basis-Bibliothek", enthält das Interface zwischen OptiVec und der BC-Laufzeitbibliothek. Bitte beachten Sie die notwendige Unterscheidung zwischen Verwendung der statischen und der dynamischen Laufzeitbibliothek in 32-bit:
 
PlattformCompilerstatische LaufzeitbibliothekLaufzeitbibliothek als DLL
Win64bcc64, ab RAD Studio 12 (2023)ovbcbase64.aovbcbase64.a
 bcc64, alle Versionen bis RAD Studio 11.xovbcx64.aovbcx64.a
Win32"klassischer" Borland Compiler bcc32
ab RAD Studio / BCB 12 (2023)
ovbcbase32s.libovbcbase32d.lib
 ältere Versionen bis einschl. 11.xvcfs.libvcfd.lib
 CLang-Borland Compiler bcc32c
ab RAD Studio 12
ovbcbase32cs.libovbcbase32cd.lib
 RAD Studio 10.x, 11.xovbc10_11base32cs.libovbc10_11base32cd.lib

Die zweite einzubindende Bibliothek wiederum ist entscheidet über die Prozessor-Unterstützung. Sie ist aber unabhängig von der jeweiligen Projekt-Konfiguration.
 
PlattformCompilerProzessorAllzweckDebugAutothreading (MP)MP + CUDA
Win64bcc64P9: Haswell+ / Excavator+OVVC64_9.a ---- OVBC64_9M.aOVBC64_9C.a
 bcc64P8: AMD64xxx, Core2xxxOVBC64_8.aOVBC64_8D.aOVBC64_8M.aOVBC64_8C.a
Win32bcc32 (klassisch)P8: AMD64xxx, Core2xxxVCF8W.LIB ---- VCF8M.LIBVCF8C.LIB
  P4: Max Kompatibilität, FPU-GenauigkeitVCF4W.LIBVCF4D.LIBVCF4M.LIB ----
 bcc32c (CLang)
ab C++ Builder 10.1 Berlin
P8: AMD64xxx, Core2xxxovbc32c_8.lib ---- ovbc32c_8m.libovbc32c_8c.lib
  P4: Max Kompatibilität, FPU-Genauigkeitovbc32c_4.libovbc32c_4d.libovbc32c_4m.lib ----
 bcc32c (CLang)
bis C++ Builder 10 Seattle
P8: AMD64xxx, Core2xxxVCF8W.LIB ---- VCF8M.LIBVCF8C.LIB
  P4: Max Kompatibilität, FPU-GenauigkeitVCF4W.LIBVCF4D.LIBVCF4M.LIB ----
 
Um die "C"-Bibliotheken (Mehrkern+CUDA) zu nutzen, müssen Sie außerdem die Import-Bibliothek OVBCCU32.lib (32-bit) oder OVBCCU64.a (64-bit) einschließen und sicherstellen, dass sich die entsprechende DLL, OVBCCU32.DLL oder OVBCCU64.DLL entweder in dem Verzeichnis befindet, in dem Sie Ihr ausfürbares Programm erstellen, oder in einem anderen Verzeichnis, dass in der Windows-Umgebungsvariablen PATH aufgeführt ist. Sollten Sie unter 64-bit noch Unterstützung für alte CUDA-Hardware (Compute Capability 3.5, 5.0, 6.0) benötigen, schließen Sie OVBCCULEG64.a anstelle von OVBCCU64.a ein, die auf die DLL OVBCCULEG64.DLL verweist.

Alle in früheren Versionen von OptiVec gültigen Einschränkungen für die Verwendung mit dem 32-bit CLang-Borland-Compiler bcc32c.exe sind aufgehoben.

Fortsetzung mit Kap. 1.5 Deklaration von OptiVec-Funktionen in C/C++

1.4.2 OptiVec für Visual C++ (Microsoft Visual Studio)

Sie müssen nicht nur eine, sondern zwei OptiVec-Bibliotheken einschließen. Die erste enthält das Interface zwischen OptiVec und der VC-Laufzeitbibliothek; sie ist spezifisch für die jeweils gewünschte Projekt-Konfiguration. Die zweite Bibliothek wiederum ist unabhängig von der jeweiligen Projekt-Konfiguration; durch sie entscheiden Sie über die Prozessor-Unterstützung.
Wählen Sie also zunächst die gewünschte Projekt-Konfiguration und Laufzeitbibliothek. Letztere finden Sie unter Projekt / (Konfigurations-)Eigenschaften / C/C++ / Code-Generation / Laufzeitbibliothek. Unter Projekt / (Konfigurations-)Eigenschaften / Linker / Eingabe fügen Sie die entsprechende OptiVec-Bibliothek Ihrem Projekt hinzu, gemäß der folgenden Tabelle.
 
PlattformVisual 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.LIBOVVCMTD.LIBOVVC9MDR.LIBOVVCMTR.LIB
 VS 2005OVVC8MDD.LIBOVVC8_12MTD.LIBOVVC8MDR.LIBOVVC8_12MTR.LIB
 
*Für die veralteten VS-Versionen 2008 und 2010 stehen keine 64-bit DebugDLL und ReleaseDLL zur Verfügung. Ersatzweise kann die Basis-Bibliothek OVVC8x64MDR.LIB verwendet werden. Zusätzlich ist hierzu das VS 2005 Redistributable erforderlich. Sie finden dieses auf www.microsoft.com/download. Geben Sie "vcredist_x64" in die Suchmaske ein, um die Liste der verfügbaren Redistributables zu erhalten und wählen Sie die VS 2005-Version. Sie werden bei dieser Vorgehensweise Linker-Warnungen zu Bibliotheks-Konflikten erhalten, können diese aber in diesem spezifischen Fall ignorieren.

Man beachte, dass es eine gewisse Inkonsistenz in den Konfigurations-Bezeichnungen von Visual Studio gibt: Die Standard-Konfigurationen "Debug" und "Release" binden die Laufzeitbibliothek und MFC als DLL ein, stellen also die in früheren Versionen "Debug DLL" und "Release DLL" genannten Konfigurationen dar. Das bedeutet, dass die OptiVec-Basisbibliotheken OVVC??MDD.lib und OVVC??MDR.lib mit diesen Konfigurationen zu benutzen sind. Außerdem muss sichergestellt sein, dass die Laufzeit- und MFC-DLL's auf jedem Rechner installiert sind, auf dem eine so erstellte Anwendung laufen soll. Für viele Anwendungen empfiehlt es sich daher, Project / Properties / Configuration Properties / C/C++ / Code Generation / Runtime Library in "Multi-Thread Debug (/MTd)" oder "Multi-Thread Release (MT)" zu ändern, um durch statisches Linken die DLL-Redistributables zu vermeiden. Dies ist in der "DebugStatic"-Konfiguration in den Demo-Dateien von OptiVec so realisiert.

Als zweites fügen Sie nun die prozessor-spezifische OptiVec-Bibliothek gemäß folgender Tabelle hinzu:
ProzessorAllzweck-BibliothekDebug-BibliothekMP / Mehr-KernMehr-Kern + CUDA64-bit Allgemein64-bit Debug64-bit Mehrkern64-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: FPU-Genauigkeit, 486DX/PentiumOVVC4.LIBOVVC4D.LIBOVVC4M.LIB ---- ---- ---- ---- ----
 
Die Bilbiotheken für Mehrprozessor-Systeme funktionieren sowohl auf Workstations mit diskreten Prozessoren der genannten Entwicklungsstufe als auch auf Mehrkern-Prozessoren (AMD64x2, Core2 Duo usw.). Damit OptiVec sowohl in Anwendungen mit MFC als auch ohne MFC verwenden werden kann, ruft es selbst nur direkt die Windows-API auf, nicht aber über den Umweg von MFC. Wenn Sie nun aber MFC verwenden (sei es als statische Bibliothek, sei es als DLL), bindet Visual C++ die benötigte Import-Bibliothek user32.lib standardmäßig nicht mit ein. Sie müssen dies daher explizit selbst tun: Die Zeile Projekt / Einstellungen / Linker / Kategorie: Allgemein / Objekt- und Bibliothek-Module muß den Eintrag user32.lib erhalten. Andernfalls würde der Linker den Fehler "error LNK2001: Nichtaufgeloestes externes Symbol __imp__MessageBoxA@??" melden.

Um die "C"-Bibliotheken (Mehrkern+CUDA) zu nutzen, müssen Sie außerdem die Import-Bibliothek OVVCCU32.lib (32-bit) oder OVVCCU64.lib (64-bit) einschließen und sicherstellen, dass sich die entsprechende DLL, OVVCCU32.DLL oder OVVCCU64.DLL entweder in dem Verzeichnis befindet, in dem Sie Ihr ausfürbares Programm erstellen, oder in einem anderen Verzeichnis, dass in der Windows-Umgebungsvariablen PATH aufgeführt ist. Sollten Sie unter 64-bit noch Unterstützung für alte CUDA-Hardware (Compute Capability 3.5, 5.0, 6.0) benötigen, schließen Sie OVVCCULEG64.lib anstelle von OVVCCU64.lib ein, die auf die DLL OVVCCULEG64.DLL verweist.

Fortsetzung mit Kap. 1.5 Deklaration von OptiVec-Funktionen in C/C++

1.4.3 OptiVec für GCC (GNU Compiler Collection), Windows


Angenommen, Ihr OptiVec-Verzeichnis sei C:\OPTIVEC, müssen Sie beim Compilieren mit GCC die Option -I C:\OPTIVEC\INCLUDE angeben.
Sie müssen nicht nur eine, sondern zwei OptiVec-Bibliotheken einschließen. Die erste (die "Basis-Bibliothek") enthält das Interface zwischen OptiVec und den GCC-Laufzeitbibliotheken; sie ist spezifisch für die jeweils gewählten GCC-Konfiguration. Die zweite Bibliothek wiederum ist unabhängig von der Compiler-Konfiguration; durch sie entscheiden Sie über die Prozessor-Unterstützung.
Wählen Sie die Basis-Bibliothek aus der folgenden Tabelle:
 
PlattformGCC-Thread-ModellGCC-Exception-ModellPassende OptiVec Basis-Bibliothek
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

Nun wählen Sie die zweite, Prozessor-spezifische OptiVec-Bibliothek aus der nächsten Tabelle:
Prozessor32-bit AllzweckDebugMP / Mehr-KernMehr-Kern + CUDA64-bit Allgemein64-bit Debug64-bit Mehrkern64-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: FPU-Genauigkeit, 486DX/Pentiumovgc32_4.libovgc32_4d.libovgc32_4m.lib ---- ---- ---- ---- ----
 
Die Bilbiotheken für Mehrprozessor-Systeme funktionieren sowohl auf Workstations mit diskreten Prozessoren der genannten Entwicklungsstufe als auch auf Mehrkern-Prozessoren (AMD64x2, Core2 Duo usw.).

Um die "C"-Bibliotheken (Mehrkern+CUDA) zu nutzen, müssen Sie zusätzlich die DLL's ovgccu32.dll (32-bit) oder ovgccu64.dll (64-bit) an den Linker übergeben. Sollten Sie unter 64-bit noch Unterstützung für alte CUDA-Hardware (Compute Capability 3.5, 5.0, 6.0) benötigen, schließen Sie ovgcculeg64.dll anstelle von ovgccu64.dll ein. Anders als alle anderen Compiler benötigt GCC keine Import-Bibliothek, sondern kann direkt gegen die DLL linken (und sich die Import-Tabelle dabei selbst erstellen). Außerdem müssen Sie sicherstellen, dass die genannten DLLs sich entweder in dem Verzeichnis befinden, in dem Sie Ihr ausfürbares Programm erstellen, oder in einem anderen Verzeichnis, dass in der Windows-Umgebungsvariablen PATH aufgeführt ist.

Ein sehr wichtiger Punkt, den es bei der Arbeit mit GCC zu beachten gilt, ist, dass der Linker gegenseitige Abhängigkeiten zwischen eingeschlossenen Bibliotheken nicht selbständig auflöst. Da die Basis-Bibliothek und die Prozessor-spezifische Bibliothek von OptiVec aber gegenseitige Abhängigkeiten enthalten, bedeutet dies, dass die beiden paarweise mindestens zweimal eingeschlossen werden müssen. Wenn Sie Linker-Fehler über nicht gefundene OptiVec-Funktionsnamen erhalten, schließen Sie einfach dasselbe Bibliotheken-Paar noch ein weiteres Mal ein. Das Makefile für die Demo-Programme mag als Beispiel dienen.

GCC ist der einzige unter den "großen" Compilern, der in 64-bit den aus 80-bit Fließkommazahlen bestehenden Datentyp long double bzw. extended unterstützt. (Die anderen Compiler benutzen in 64-bit long double / extended einfach als Synonym für double). Dies ist ein sehr wertvolles Feature von GCC, da die zusätzliche Genauigkeit und Reichweite gelegentlich eine bedeutende Vereinfachung darstellen können. OptiVec unterstützt diesen Datentyp mit den VE_, VCE_, VPE_, ME_, und MCE_ Funktionen.

Die Linux-Version von OptiVec ist weiter unten beschrieben.

Fortsetzung mit Kap. 1.5 Deklaration von OptiVec-Funktionen in C/C++

1.4.4 OptiVec für LLVM CLang


Angenommen, Ihr OptiVec-Verzeichnis sei C:\OPTIVEC, müssen Sie beim Compilieren mit CLang die Option -I C:\OPTIVEC\INCLUDE angeben.
Sie müssen nicht nur eine, sondern zwei OptiVec-Bibliotheken einschließen. Die erste (die "Basis-Bibliothek") enthält das Interface zwischen OptiVec und den CLang-Laufzeitbibliotheken. (Tatsächlich benutzt CLang großenteils die Laufzeitbibliothek von Visual C++ und ist "fast" kompatibel mit Visual C++. Diese Kompatibilität ist aber so weit nur "fast" gegeben, dass OptiVec eine eigene Version für CLang benötigt). Die OptiVec-Basis-Bibliothek ist ovclbase64.lib für 64-bit und ovclbase32.lib für 32-bit.
Die zweite Bibliothek wiederum entscheidet über die Prozessor-Unterstützung.
Prozessor32-bit AllzweckDebugMP / Mehr-KernMehr-Kern + CUDA64-bit Allgemein64-bit Debug64-bit Mehrkern64-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: FPU-Genauigkeit, 486DX/Pentiumovcl32_4.libovcl32_4d.libovcl32_4m.lib ---- ---- ---- ---- ----
 
Die Bilbiotheken für Mehrprozessor-Systeme funktionieren sowohl auf Workstations mit diskreten Prozessoren der genannten Entwicklungsstufe als auch auf Mehrkern-Prozessoren (AMD64x2, Core2 Duo usw.).

Um die "C"-Bibliotheken (Mehrkern+CUDA) zu nutzen, müssen Sie zusätzlich die Importbibliotheken ovvccu32.lib (32-bit) oder ovvccu64.lib (64-bit) an den Linker übergeben, die auf ovvccu32.dll bzw. ovvccu64.dll verweisen. Sollten Sie unter 64-bit noch Unterstützung für alte CUDA-Hardware (Compute Capability 3.5, 5.0, 6.0) benötigen, schließen Sie ovvcculeg64.lib anstelle von ovvccu64.lib ein, die auf die DLL ovvcculeg64.dll verweist. Außerdem müssen Sie sicherstellen, dass die genannten DLLs sich entweder in dem Verzeichnis befinden, in dem Sie Ihr ausfürbares Programm erstellen, oder in einem anderen Verzeichnis, dass in der Windows-Umgebungsvariablen PATH aufgeführt ist. Falls Sie sich über den auf Visual C++ hinweisenden Bibliotheksnamen ovvccu??.lib wundern – in der Tat werden die cudaOptiVec-Bibliotheken für Visual C++ auch für CLang verwendet.

Die Linux-Version von OptiVec ist weiter unten beschrieben.

Fortsetzung mit Kap. 1.5 Deklaration von OptiVec-Funktionen in C/C++

1.4.5 OptiVec für Delphi

Die Auswahl zwischen den verschiedenen OptiVec-Bibliotheken erfolgt durch die Auswahl des entsprechenden Unit-Suchpfades. Die 32-bit units (.DCU Dateien) befinden sich in den Verzeichnissen OPTIVEC\LIB4D,  OPTIVEC\LIB8M usw. Die 64-bit units sind in den Verzeichnissen OPTIVEC\Win64\LIB8,  OPTIVEC\LIB9C usw.
 
In der registrierten Vollversion habe Sie die Wahl zwischen den folgenden Bibliotheken:
Prozessor32-bit AllgemeinDebugAutothreading (Multi-Proc.)MP + CUDA64-bit Allgemein64-bit Debug64-bit Multi-Proc.64-bit MP+CUDA64-bit MP+alte CUDA
P9: Haswell+ / Excavator+ ---- ---- ---- ---- Win64\LIB9 ---- Win64\LIB9MWin64\LIB9C ----
P8: AMD64xxx, Core2xxxLIB8 ---- LIB8MLIB8CWin64\LIB8Win64\LIB8DWin64\LIB8MWin64\LIB8CWin64\LIB8Cleg
P4: FPU-Genauigkeit, 486DX/PentiumLIB4LIB4DLIB4M ---- ---- ---- ---- ---- ----
 

Um die "C"-Units (Mehrkern+CUDA) zu nutzen, müssen Sie außerdem sicherstellen, dass sich OVDCU32.DLL (32-bit), OVDCU64.DLL (64-bit) oder OVDCULEG64.DLL (64-bit für alte CUDA-Devices mit Compute Cap. 3.5, 5.0, 6.0) entweder in dem Verzeichnis befindet, in dem Sie Ihr ausfürbares Programm erstellen, oder in einem anderen Verzeichnis, dass in der Windows-Umgebungsvariablen PATH aufgeführt ist.

Fortsetzung mit Kap. 1.5.2 Deklaration von OptiVec-Funktionen in Pascal / Delphi

1.4.6 OptiVec für Lazarus / FreePascal

Auch für Lazarus erfolgt die Auswahl zwischen den verschiedenen OptiVec-Bibliotheken durch die Auswahl des entsprechenden Unit-Suchpfades (unter "Other Units" einzutragen). Die Shareware-Version stellt zwei Sätze von Units (.PPU-Dateien samt einzubindenden Object-Dateien *.o)zur Verfügung, eine im Verzeichnis LIB8, die andere in LIB9M.
In der registrierten Vollversion habe Sie die Wahl zwischen den folgenden Bibliotheken:
ProzessorAllgemeinDebugAutothreading (Multi-Processor)MP + CUDAMP + alte CUDA
P9: Haswell+ / Excavator+LIB9 --- LIB9MLIB9C ---
P8: AMD64xxx, Core2xxxLIB8LIB8DLIB8MLIB8CLIB8Cleg
 

Um die "C"-Units (Mehrkern+CUDA) zu nutzen, müssen Sie außerdem sicherstellen, dass sich OVDCU64.DLL (für aktuelle CUDA-Devices) oder OVDCULEG64.DLL (für alte CUDA-Devices mit Compute Capability 3.5, 5.0, 6.0) entweder in dem Verzeichnis befindet, in dem Sie Ihr ausfürbares Programm erstellen, oder in einem anderen Verzeichnis, dass in der Windows-Umgebungsvariablen PATH aufgeführt ist.

Fortsetzung mit Kap. 1.5.2 Deklaration von OptiVec-Funktionen in Pascal / Delphi

1.4.7 OptiVec für Linux mit GCC oder CLang

Auch hier müssen zwei OptiVec-Bibliotheken eingebunden werden. Die erste (die "Basis-Bibliothek") enthält das Interface zwischen OptiVec und der glibc-Laufzeitbibliothek.
Die zweite Bibliothek wiederum entscheidet über die Prozessor-Unterstützung.
Zuerst wähle man die Basis-Bibliothek:
 
PlattformThreadingOptiVec-Basis-Bibliothek
Linux 64Single-threadovlxcbase64s.a
 Multi-threadovlxcbase64m.a

Dann wähle man die zweite, prozessor-spezifische OptiVec-Bibliothek aus folgender Tabelle:
ProcessorAllgemeinDebugMulti-Proc. Auto-Threading
P9: Haswell+ / Excavator+ovlxc64_9.a ---- ovlxc64_9m.a
P8: AMD64xxx, Core2xxxovlxc64_8.aovlxc64_8d.aovlxc64_8m.a
 
Die Autothreading-Bibliotheken können nur gemeinsam mit der Basis-Bibliothek ovlxcbase64m.a verwendet werden und erfordern die Linker-Option -lpthread.

Ein sehr wichtiger Punkt, den es bei der Arbeit mit Linux-GCC und -CLang zu beachten gilt, ist, dass der Linker gegenseitige Abhängigkeiten zwischen eingeschlossenen Bibliotheken nicht selbständig auflöst. Da die Basis-Bibliothek und die Prozessor-spezifische Bibliothek von OptiVec aber gegenseitige Abhängigkeiten enthalten, bedeutet dies, dass die beiden paarweise mindestens zweimal eingeschlossen werden müssen. Wenn Sie Linker-Fehler über nicht gefundene OptiVec-Funktionsnamen erhalten, schließen Sie einfach dasselbe Bibliotheken-Paar noch ein weiteres Mal ein. Das Makefile für die Demo-Programme mag als Beispiel dienen.

1.5 Deklaration von OptiVec-Funktionen

1.5.1 Deklaration von OptiVec-Funktionen in C/C++

Benutzen Sie die #include-Direktive, um die in Kap. 7 beschriebenen Include-Datein einzuschließen.
Um die ganze OptiVec-Bibliothek samt objekt-orientierten Interface auf einmal einzuschließen, deklariere man
#include <OptiVec.h>
Um alle Vektorfunktionen (ohne objekt-orientiertes Interface) zu erhalten,
#include <VecAll.h>
Um alle Datenanpassungs- und Matrix-Funktions hinzuzufügen,
#include <MatAll.h>.
Falls Sie MFC verwenden, müssen alle OptiVec-Include-Dateien nach(!) den Include-Dateien von MFC angegeben werden.

1.5.2 Deklaration von OptiVec-Funktionen in Pascal / Delphi

Nehmen Sie die OptiVec-Units mit der "uses"-Anweisung in Ihr Programm auf. Die OptiVec-units sind nach Datentypen geordnet, siehe Kap. 7. In Delphi sollten die OptiVec-Units immer zusammen mit der Unit WinProcs verwendet werden, in Lazarus mit LCLType, da OptiVec einige Datentypen von hier "borgt".

1.6 Beispiel-Programme

Schauen Sie die Beispielprogramme an: Nach diesen Vorbereitungen stehen Ihnen alle Funktionen von OptiVec für Ihre Programme zur Verfügung.
Sollten Sie OptiVec einmal wieder von Ihrem Computer entfernen wollen, führen Sie bitte UNINSTAL.EXE aus oder löschen das gesamte Verzeichnis OPTIVEC mit allen Unterverzeichnissen.

Zurück zum Inhaltsverzeichnis


2. Elemente von VectorLib-Funktionen

2.1 Synonyme einiger Datentypen

Um größtmögliche Flexibilität und Vollständigkeit von OptiVec zu gewährleisten, wurden zusätzliche Datentypen in <VecLib.h> bzw. der Unit VecLib eingeführt:

a) nur C/C++:

Der Datentyp ui (kurz für "unsigned index") wird für die Indizierung von Arrays benutzt und ist in <VecLib.h> als Synonym für size_t definiert, also für Win32 als unsigned int bzw. für Win64 als unsigned __int64.

64-bit-Integers (__int64 in BC++ Builder und MS Visual C++, Int64 in Delphi, früher einmal Comp in Turbo Pascal) werden in OptiVec als quad (für "quadruple integer", also Vierfach-Integer) bezeichnet.
Der Datentyp quad ist in 32-bit immer vorzeichenbehaftet; nur für Win64 bietet OptiVec den Datentyp uquad als vorzeichenlosen 64-bit Ganzzahltyp.

Der Pascal/Delphi-Benutzern wohlbekannte Datentyp extended wird in der Borland C++-Version von OptiVec als Synonym für long double verwendet. Da weder Visual C++ noch die meisten 64-bit-Compiler 80-bit-Fließkommazahlen unterstützen, ist extended hier als double definiert.
Der Grund für die Einführung des Typs extended ist, daß alle OptiVec-Funktionen identische Namen in C/C++ und Pascal/Delphi haben sollen. Die Funktions-Präfixe aber sind vom Datentyp der verarbeiteten Vektoren abgeleitet (s.u.). Der Buchstabe "L" (der vielleicht für long double stehen könnte) ist bereits durch long int und unsigned long überbelegt. So bietet sich der Buchstabe "E" für extended an, was den zusätzlichen Vorteil der Nähe zu den Buchstaben "D" für double und "F" für float hat. Es ist vorgesehen, in der Zukunft 128-bit-Fließkommazahlen (__fp128 / __float128) als "G" für Great und Half Floats (__fp16) als "H" ihren Platz ebenfalls in alphabetischer Nachbarschaft finden zu lassen.

b) nur Pascal/Delphi:

Der Datentyp Float wird von C/C++ als Synonym für Single übernommen. Wir ziehen es vor, die Buchstaben, die die Fließkomma-Datentypen bezeichnen, in alphabetischer Nachbarschaft zu haben: "D" für Double, "E" für Extended und "F" für Float. Wie oben erwähnt, können künftig 128-bit-Fließkommazahlen (__fp128 / __float128) ihren Platz in dieser Reihe als "G" für Great und Half Floats (__fp16) als "H" finden.

Aus "historischen" Gründen weisen die Ganzzahl-Datentypen eine etwas konfuse Nomenklatur in Pascal/Delphi auf. Um die vom Datentyp abgeleiteten Präfixe mit der C/C++-Version von OptiVec kompatibel zu machen, definieren wir eine Anzahl von Synonymen, wie in der folgenden Tabelle beschrieben:
typePascal/Delphi-NameSynonymabgeleitetes Präfix
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 UInt64UQuadVUQ_
16/32 bit signedInteger VI_
16/32 bit unsignedCardinalUIntVU_

UQuads existieren nur in der 64-bit-Version. Für Win32 gibt es nur den vorzeichenbehafteten Typ Quad.

Um einen Bool'schen Datentyp derselben Größe wie Integer zur Verfügung zu haben, definieren wir den Typ IntBool. Er ist äquivalent mit LongBool. Man findet den Typ IntBool vor allem als Rückgabewert vieler mathematischer VectorLib-Funktionen.

2.2 Komplexe Zahlen:
Die Datentypen fComplex, dComplex, eComplex, fPolar, dPolar und ePolar

Bezüglich der Unterstützung komplexer Zahlen herrscht ein gewisses Durcheinander in den gebräuchlichen Programmier-Sprachen. Der ANSI-Standard von C bietet lediglich eine Struktur complex (für aus doubles bestehende Real- und Imaginärteile). Borland C fügt dem eine Struktur _complexl für aus long doubles bestehende komplexe Zahlen hinzu. Real- und Imaginärteil werden dabei als x und y bezeichnet. Die einzige vorhandene Funktion für komplexe Zahlen ist die Bildung des Absolutwertes.
Schon seit frühen Versionen bot Borland C++ die Klasse complex, die mit doubles arbeitet. Hier sind Real- und Imaginärteil nur über die Funktionen real und imag zugänglich. Die Klasse complex bietet eine ganze Reihe arithmetischer Operationen und mathematischer Funktionen.
Erst die Standard C++ Library definierte komplexe Klassen für alle drei Genauigkeiten.
Delphi bietet eine Unit Complex, die komplexe Zahlen als Varianten-Typen führt – mit allen dadurch verursachten Ineffizienzen.
Komplexe Funktionen in Polarkoordinaten werden bislang von keinem dieser Produkte geboten.
In den meisten Compilern sind die komplexen Operationen sehr ineffizient und vor allem ungenau implementiert (nur die Lehrbuchformel einer komplexen Funktion hinzuschreiben, wie es meist geschieht, wird nur für einen sehr begrenzten Bereich von Argumenten brauchbare Ergebnisse liefern!).

Unsere Ziele sind

Hierfür wurde die Bibliothek CMATH geschaffen und wird mit OptiVec ausgeliefert. Sie wird in der Datei CMATHD.HTM näher beschrieben. Wenn Sie irgendeine der nicht-vektorisierten Funktionen von CMATH mit C/C++ benutzen, müssen Sie <newcplx.h> (für C++-Module) oder <cmath.h> (für einfache C-Module) vor (!) den übrigen OptiVec-Include-Dateien einschließen.
Auch ohne explizite Einbindung von CMATH stellt OptiVec die grundlegenden Datentypen und Initialisierungs-Möglichkeiten in <VecLib.h> bzw. der Unit VecLib zur Verfügung. Falls Sie nur diese verwenden, brauchen Sie CMATH nicht explizit einzuschließen.
Die für C/C++ in <VecLib.h> definierten komplexen Typen lauten:
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;

(Der Datentyp extended wird als Synonym für long double verwendet, s. oben.)

Die entsprechenden Definitionen für Pascal/Delphi sind in der Unit VecLib enthalten:
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;

Komplexe Zahlen werden initialisiert, indem ihrem Real- und Imaginärteil bzw. ihrem Mag- und Arg-Teil die gewünschten Werte zugewiesen werden, z.B.:
z.Re  = 3.0; z.Im  = 5.7;
p.Mag = 8.8; p.Arg = 3.14;

(Für Pascal/Delphi muß der Zuweisungs-Operator natürlich ":=" geschrieben werden).
Alternativ kann die Initialisierung auch mittels der Funktionen fcplx oder fpolr durchgeführt werden:
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 );

oder:
z := fcplx( 3.0, 5.7 );
p := fpolr( 3.0, 5.7 );

Für doppelt-genaue komplexe Zahlen gebrauche man dcplx und dpolr, für extended-genaue ecplx und epolr.
Zeiger auf komplexe Felder oder Vektoren werden mithilfe der Datentypen cfVector, cdVector und ceVector (für cartesisch-komplexe Vektoren) sowie pfVector, pdVector und peVector (für Vektoren komplexer Zahlen in Polarkoordinaten) definiert, wie unten beschrieben.

2.3 Vektoren und Arrays:
Die Datentypen fVector, dVector, eVector,
cfVector, cdVector, ceVector, pfVector, pdVector, peVector,
iVector, biVector, siVector, liVector, qiVector,
uVector, ubVector, usVector, ulVector, uqVector und uiVector

Wie üblich definieren wir einen "Vektor" als ein eindimensionales Daten-Feld (oder Array), das aus mindestens einem Element besteht(!) und dessen Elemente alle demselben Datentyp angehören. Etwas mathematischer definiert ist ein Vektor ein Tensor vom Rang 1. Ein zweidimensionales Feld (also ein Tensor vom Rang 2) wird hier als "Matrix" bezeichnet, höher-dimensionale Felder generell als Tensoren.
Im Unterschied zu anderen Ansätzen erlaubt VectorLib keine Vektoren der Länge 0!

Die Basis aller VectorLib-Funktionen bilden die Vektor-Datentypen, die in <VecLib.h> bzw. der Unit VecLib definiert und unten aufgelistet sind. Im Unterschied zu den statischen Arrays, die immer eine beim Compilieren festgelegte Größe besitzen, arbeiten die VectorLib-Typen mit dynamischer Speicherzuweisung und daher mit variablen Größen. Wegen dieser Flexibilität empfehlen wir den vorzugsweisen Gebrauch der letzteren. Hier sind sie also:
 
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;

Intern handelt es sich also bei einem Datentyp wie fVector um einen "Zeiger auf float". Man sollte ihn sich allerdings lieber als "float-Vector" vorstellen.
 
N.B.: In der Windows-Programmierung wird häufig der Buchstabe "l" oder "L" eingesetzt, um long int-Variablen zu bezeichnen. Um Verwechslungen vorzubeugen, wird hier für long int stets das aus zwei Buchstaben bestehende Kürzel "li" oder "LI" verwendet und für unsigned long das Kürzel "ul" oder "UL". Konflikte mit den Präfixen für long double-Vektoren werden durch Ableitung deren Kürzel vom Alias-Namen extended und den Gebrauch von "e", "ce", "E" und "CE" umgangen, wie bereits oben und auch in den folgenden Abschnitten beschrieben.
 
Delphi bietet zusätzlich auch dynamisch allozierte Arrays, die ebenfalls als Argumente an OptiVec-Funktionen übergeben werden können. Die folgende Tabelle vergleicht die Zeiger-basierten Vektoren von VectorLib mit den verschiedenen Array-Typen von Pascal/Delphi:
 
 OptiVec-VektorenPascal/Delphi-Arrays (statisch/dynamisch)
Ausrichtung des ersten Elementsan 64-byte-Grenze für optimale Cache-Zeilen-Anpassung2- oder 4-byte-Grenze (kann Zeilenumbruchs-Strafzyklen für double, QuadInt zur Folge haben)
Ausrichtung folgender Elementegepackt (d.h. keine Dummy-Bytes zwischen Elementen, auch nicht für 10- und 20-bit-Typen)Arrays müssen in Delphi als "packed" deklariert werden, um kompatibel mit OptiVec zu sein
Index-Bereichsprüfungkeineautomatisch mittels eingebauter Größeninformation
dynamische Speicherzuweisungfunction VF_vectorVF_vector0procedure SetLength
Initialisierung mit 0optional durch Aufruf von VF_vector0immer
Freigabefunction V_freeV_freeAllprocedure Finalize
einzelne Elemente lesenfunction VF_element:
a := VF_element(X,5);
typecast in Array ebenfalls möglich:
a := fArray(X)[5];
Index in eckigen Klammern:
a := X[5];
einzelne Elemente schreibenfunction VF_setElement:
VF_setElement(X,5,a);
typecast in Array ebenfalls möglich:
fArray(X)[5] := a;
Index in eckigen Klammern:
X[5] := a;
Übergabe an OptiVec-Funktiondirekt:
VF_equ1( X, sz );
Adress-Operator:
VF_equ1( @X, sz );
Übergabe von Subvektor an OptiVec-Funktionfunction VF_Pelement:
VF_equC( VF_Pelement(X,10), sz−10, 3.7);
Adress-Operator:
VF_equC( @X[10], sz−10, 3.7 );
 
Zusammenfassend läßt sich sagen, daß die Pascal/Delphi-Arrays etwas bequemer zu verwenden und durch die Index-Bereichsprüfung auch sicherer sind, während die Zeiger-basierten OptiVec-Vektoren schneller verarbeitet werden können (durch die bessere Speicherausrichtung und den Fortfall der Index-Bereichsüberprüfung).

Zurück zum Inhaltsverzeichnis

2.4 Vektor-Funktionen reeller Zahlen:
Die Präfixe VF_,  VD_ und VE_

Wie bereits angedeutet, wird der Datentyp, mit dem eine OptiVec-Funktion arbeitet, durch ihr Präfix angegeben. Für die drei Fließkomma-Datentypen der 80x87-Familie, also für float, double und extended (long double) gelten die Funktions-Präfixe VF_,  VD_ und VE_, wobei das "V" für "Vektor-Funktion" steht und der folgende Buchstabe den Datentyp bezeichnet. Der "Kern" des Funktionsnamens ist von diesem Präfix (zwecks besserer Lesbarkeit der Programme) durch einen Unterstrich abgesetzt. Jede Funktion arbeitet ausschließlich innerhalb einer der drei Fließkomma-Genauigkeiten.

Zum Präfix VF_ gehören Argumente vom Typ float und fVector, zu VD_ gehören double und dVector und natürlich entsprechend zu VE_ extended und eVector als Argumente und Rückgabewerte.

In den folgenden Kapiteln und in der Funktionsreferenz ist meist nur die VF_- Version einer Funktion explizit beschrieben. Die VD_- und VE_-Versionen sind dieser exakt analog. Man hat nur "fVector" durch "dVector" bzw. "eVector" zu ersetzen und "float" durch "double" bzw. "extended".

Zurück zum Inhaltsverzeichnis

2.5 Komplexe Funktionen:
Die Präfixe VCF_,  VCD_,  VCE_,  VPF_,  VPD_ und VPE_

Präfixe mit einem "C" als zweitem Buchstaben bezeichnen Funktionen cartesisch-komplexer Vektoren. Ist der zweite Buchstabe ein "P", so handelt es sich um eine komplexe Funktion in Polarkoordinaten. Ganz ähnlich wie bei den im vorigen Abschnitt beschriebenen reellen Funktionen gehören zu dem Präfix VCF_ Funktionen, die ausschließlich in einfacher Genauigkeit arbeiten, also Argumente und Rückgabewerte der Typen float, fComplex, fVector und cfVector besitzen. Entsprechendes gilt für die übrigen oben genannte Präfixe.

Rückgabewerte der komplexen Datentypen sind in Pascal/Delphi nicht möglich. Daher unterscheidet sich die Syntax komplexer Funktionen, die Werte zurückgeben, in C/C++ und Pascal/Delphi.

Im Unterschied zu der Sorglosigkeit, mit der komplex-mathematische Funktionen meist behandelt werden, sind die komplexen Funktionen von OptiVec so geschrieben, daß die volle Genauigkeit über den gesamten für den jeweiligen Datentyp legalen Bereich von Eingabe-/Ausgabewerten gewährleistet ist.

Wie bereits erwähnt, sind die nicht-vektorisierten komplexen Funktionen in der Datei CMATHD.HTM beschrieben.

Zurück zum Inhaltsverzeichnis

2.6 Funktionen der Ganzzahl-Datentypen:
Die Präfixe VI_,  VBI_,  VSI_,  VLI_,  VQI_,
VU_,  VUB_,  VUS_,  VUL_,  VUQ_ und VUI_

Wie aus den vorangegangenen Erläuterungen wohl bereits zu erahnen, arbeitet jede der Integer-Funktionen von VectorLib innerhalb eines bestimmten Datentyps. Die Zuordnung ist die folgende:
Präfix VBI_: Datentyp char (oder byte) / ByteInt,
Präfix VSI_: Datentyp short int / SmallInt,
Präfix VI_: Datentyp int / Integer,
Präfix VLI_: Datentyp long int / LongInt (32-bit für Windows, 64-bit für Linux)
Präfix VQI_: Datentyp quad / QuadInt.

Für die vorzeichenlosen Ganzzahl-Typen gilt analog:
Präfix VUB_: Datentyp unsigned char (unsigned byte) / UByte,
Präfix VUS_: Datentyp unsigned short / USmall,
Präfix VU_: Datentyp unsigned / UInt,
Präfix VUL_: Datentyp unsigned long / ULong, (32-bit für Windows, 64-bit für Linux)
Präfix VUQ_: Datentyp uquad / UQuad (nur für Win64 und Linux),
Präfix VUI_: Datentyp ui.

Man erschrecke nicht vor dieser Vielfalt. Es gehört zu den Stärken moderner Computer-Sprachen, über diese vielen Datentypen zu verfügen. Gleichzeitig kann diese Stärke natürlich eine Schwäche bedeuten, denn sie verführt zu einem Programmierstil, in dem die Datentypen so lange vermischt werden, bis der Durchblick verloren geht. Im Normalfall sollten die VI_-,  VLI_-,  VU_- und VUI_- Versionen vollauf genügen. Es ist aber nicht schlecht zu wissen, daß noch mehr zur Verfügung stehen, wenn man sie denn benötigt.

Sofern sie existieren, sind die mit Ganzzahlen arbeitenden VectorLib-Funktionen gemeinsam mit ihren Fließkomma-Schwestern besprochen. Auch auf die Gefahr hin, Sie zu langweilen: Die VI_-Version gewinnt man aus der VF_-Version durch Ersatz aller "float"-Parameter durch "int" und aller "fVector" durch "iVector". Gleiches gilt für alle anderen Ganzzahl-Typen.

Zurück zum Inhaltsverzeichnis

2.7 Gemeinsame Funktionen mehrerer Datentypen: Das PräfixV_

Einige Funktionen von VectorLib sind entweder nicht auf einen bestimmten Datentyp bezogen oder dienen der Umwandlung eines Datentyps in einen anderen. Ihnen kommt das Präfix V_ zu. Funktionen wie V_initPlot und V_free gehören zur ersten Gruppe – die Initialisierung der Plot-Routinen ist unabhängig vom Datentyp der darzustellenden Vektoren. Eine Funktion wie V_LItoD gehört dagegen zur zweiten Gruppe; hier werden die Elemente eines liVector (also long ints) in doppelt-genaue Fließkommazahlen umgewandelt und in einem dVector gespeichert. Die typ-unabhängigen Funktionen finden sich in den Include-Dateien <VecLib.h> und <Vgraph.h> bzw. den Units VecLib und VGraph, die Datenumwandlungs-Funktionen in der zum jeweiligen Ziel-Typ gehörenden Include-Datei bzw. Unit.

Zurück zum Inhaltsverzeichnis


3. Nur C++: VecObj, das objekt-orientierte Interface für VectorLib

VecObj, das objekt-orientierte C++-Interface für die Vektorfunktionen von OptiVec, wurde von Brian Dale, Case Western Reserve University, geschrieben. Die Erweiterung hiervon für Matrizen ist als MatObj ebenfalls vorhanden.
VecObj bietet u.a. die folgenden Vorzüge: Es gibt allerdings auch einige wenige Nachteile, die wir nicht verschweigen möchten: VecObj ist in den Include-Dateien <VecObj.h>, <fVecObj.h>, <dVecObj.h> etc. enthalten mit einer Include-Datei für jeden der in OptiVec unterstützten Datentypen.
Um das gesamte Interface (für alle Datentypen zusammen) zu laden, deklariere man
#include <OptiVec.h>.
Um irgendeine der Graphik-Funktionen von VectorLib zu verwenden, sollte stets <OptiVec.h> eingeschlossen werden.

MS Visual C++ und Borland C++ Builder (nicht aber frühere Borland C++-Versionen): Die Direktive
"using namespace OptiVec;"
sollte entweder im Funktionskörper jeder ein tVecObj verwendenden Funktion oder im globalen Deklarationsteil eines Programmes auftauchen. Der Platz in den einzelnen Funktionskörpern ist sicherer, da er potentielle Namespace-Konflikte mit anderen Funktionen vermeidet.
Die Vektor-Objekte werden als classes vector<T> implementiert, die die Vektor-Adresse (den Zeiger) und seine Größe size kapseln.
Für einfachere Verwendung wurden diesen Klassen Alias-Namen zugewiesen als fVecObj, dVecObj usw., wobei der Datentyp wie sonst in OptiVec durch den ersten oder die ersten beiden Buchstaben des Klassennamens angezeigt wird.

Alle VectorLib für einen bestimmten Datentyp definierten Funktionen sind als Member-Funktionen der betreffenden class tVecObj enthalten.
Die Konstruktoren können vier Formen annehmen:
vector(); // kein Speicher zugewiesen; size auf 0 gesetzt
vector( ui size ); // Vektor von size Elementen erzeugt
vector( ui size, T fill ); // desgleichen, aber mit "fill" initialisiert
vector( vector<T> init ); // erzeugt eine Kopie des Vektors "init"

Für alle Vektor-Klassen sind die arithmetischen Operatoren
+    -    *    /    +=    -=    *=    /=
definiert, mit der Ausnahme, daß für die polar-komplexen Vektor-Klassen nur Multiplikationen und Divisionen, nicht aber Addition und Subtraktion unterstützt werden. Diese Operatoren stellen den einzigen Fall dar, in dem das Ergebnis einer Berechnung direkt einem Vektor-Objekt zugewiesen werden kann, wie z.B.
fVecObj Z = X + Y; oder
fVecObj Z = X * 3.5;
Man beachte aber, daß die Syntax-Regeln von C++ eine wirklich effiziente Implementierung dieser Operatoren nicht zulassen. Die arithmetischen Member-Funktionen sind wesentlich schneller. Wenn es auf Rechengeschwindigkeit ankommt, benutze man daher die letzteren anstelle der Operatoren-Syntax:
fVecObj Z.addV( X, Y ); oder
fVecObj Z.mulC( X, 3.5 );

Der Operator * bedeutet Multiplikation der einzelnen Elemente miteinander und nicht das Skalarprodukt zwier Vektoren.

Alle übrigen arithmetischen und mathematischen Funktionen können nur als Member-Funktion des betreffenden Ausgabe-Vektors aufgerufen werden, wie z.B. Y.exp(X). Obwohl es sicher logischer wäre, auch diese Funktionen so zu definieren, daß man stattdessen "Y = exp(X)" schreiben könnte, wurde die Syntax der Member-Funktionen gewählt, da sie wesentlich effizienter implementiert werden kann: Der einzige Weg, die zweite Variante zu implementieren, besteht darin, das Ergebnis der jeweiligen Funktion in einem temporären Vektor zwischenzuspeichern, der anschließend in Y kopiert wird. Hierdurch werden Rechenaufwand und Speicheranforderungen erhöht. Wir sind aber an Ihrer Meinung interessiert: Würden Sie trotzdem die Syntax "Y = func(X);" gegenüber der Member-Funktions-Syntax "Y.func(X);" vorziehen und ihre Nachteile in Kauf nehmen wollen? Bitte senden Sie uns Ihren Kommentar an support@optivec.com. Diese Syntax könnte in späteren Versionen von VecObj zur Verfügung gestellt werden.

Während die meisten VecObj-Funktionen Member-Funktionen des Ausgabe-Vektors sind, gibt es einige Funktionen, die gar keinen Ausgabe-Vektor haben. In diesen Fällen sind die Funktionen Member-Funktionen eines Eingabe-Vektors.
Beispiel: s = X.mean();.

Sollten Sie einmal in die Lage kommen, ein VecObj-Vektorobjekt mit einer "klassischen" C-VectorLib-Funktion verarbeiten zu wollen (z.B., um nur einen Teil zu verarbeiten), rufen Sie bitte die Member-Funktionen
getSize() für die Vektorlänge,
getVector() für den Zeiger (vom Typ tVector)  oder
Pelement( n ), um einen Zeiger auf das n'te Element zu bekommen.

Die Syntax aller VecObj-Funktionen wird in FUNKREF.HTM zusammen mit den zugrundeliegenden VectorLib-Funktionen behandelt, die von tVecObj gekapselt werden.

Zurück zum Inhaltsverzeichnis


4. VectorLib-Funktionen: Ein kurzer Überblick

4.1 Erzeugung, Initialisierung und Freigabe von Vektoren

VectorLib erlaubt die gleichzeitige Verwendung von statisch (wie z.B. "float a[100];" ) und dynamisch mit Speicherplatz versehenen Vektoren (siehe Kap. 2.3). Wir empfehlen allerdings die Verwendung der flexibleren in VectorLib definierten Vektoren mit dynamischer Speicherzuweisung. Die hierzu verwendeten Funktionen werden in der folgenden Tabelle zusammengefaßt.
VF_vectorSpeicherzuweisung für einen Vektor
VF_vector0Speicherzuweisung in Initialisierung aller elemente mit 0
V_freeeinen Vektor freigeben
V_nfreemehrere Vektoren freigeben (nur C/C++)
V_freeAllelle existierenden Vektoren freigeben
 
Man sollte stets darauf achten, Vektoren freizugeben, wenn sie nicht länger benötigt werden. Intern werden alle Vektoren in eine Tabelle eingetragen, die über den zugewiesenen Speicher Buch führt. Der Versuch, einen nicht (mehr) existierenden Vektor freizugeben, führt zu einer Warnung, nach der der Programmablauf fortgesetzt wird, ohne etwas freizugeben.

Daß den bereits in C und C++ reichlich vorhandenen Operatoren und Funktionen für diese Zwecke (malloc, calloc, free, new, LocalAlloc, GlobalAlloc usw.) hier noch mehr hinzugefügt werden, hat seinen Grund darin, daß für jedes Speichermodell und jede Umgebung automatisch die optimale Methode gewählt werden soll. Die Implementation von VF_vector usw. paßt sich also der jeweiligen Umgebung an, was der Portabilität der Programme zugute kommt.

Performance-Tips:

Zur Initialisierung ganzer Vektoren (nach der Zuweisung von Speicherplatz!) mit bestimmten Werten stehen die folgenden Funktionen zur Verfügung:
VF_equ0setzt alle Elemente gleich 0
VCF_Reequ0setzt alle Realteile gleich 0, wobei die Imaginärteile unverändert bleiben
VCF_Imequ0setzt alle Imaginärteile gleich 0, wobei die Realteile unverändert bleiben
VF_equ1setzt alle Elemente gleich 1
VF_equm1setzt alle Elemente gleich −1
VF_equCsetzt alle Elemente gleich C
VF_equVmacht einen Vektor zur Kopie eines anderen
VFx_equVerweiterte Version des Gleichheitsoperators: Yi = a * Xi + b
VF_ramp"Rampe": Xi = a * i + b.
VUI_ramp"Index-Rampe": Xi = i  (nur VUI_ und VU_-Versionen)
VF_randomLCZufallszahlen hoher Qualität
VF_randomvereinfachte Form von VF_randomLC für Zufallszahlen hoher Qualität
VF_noiseLCweißes Rauschen
VF_noisevereinfachte Form von VF_noiseLC für weißes Rauschen
VF_comb"Kamm", der an äquidistanten Punkten gleich einer Konstanten C und ansonsten 0 ist.
 

Die folgenden Funktionen dienen dem Zugriff auf einzelne Vektor-Elemente: 
VF_Pelementgibt einen Zeiger auf das durch seinen Index bestimmte Vektor-Element zurück
VF_elementgibt ein bestimmtes Vektor-Element zurück
VF_getElementkopiert ein bestimmtes Vektor-Element in eine Variable
VF_setElementsetzt ein Vektor-Element auf einen neuen Wert
VF_accElementX[i] += c; addiert einen Wert zu einem Vektor-Element
VF_decElementX[i] -= c; subtrahiert einen Wert von einem Vektor-Element
 
Die folgenden Funktionen generieren Fenster zur Verwendung in der Spektrenanalyse (siehe VF_spectrum):
VF_HannHann-Fenster
VF_ParzenParzen-Fenster
VF_WelchWelch-Fenster
 
Komplexe Vektoren können mittels der folgenden Funktionen initialisiert werden:
VF_ReImtoCzwei reelle Vektoren, Re und Im, zu einem cartesisch-komplexen Vektor zusammenfassen
VF_RetoCRealteil eines cartesisch-komplexen Vektors überschreiben
VF_ImtoCImaginärteil eines cartesisch-komplexen Vektors überschreiben
VF_PolartoCCartesisch-komplexen Vektor aus Polarkoordinaten konstruieren, die als getrennte Vektoren Mag und Arg vorliegen
VF_MagArgtoPzwei reelle Vektoren, Mag und Arg, zu einem polar-komplexen Vektor zusammenfassen
VF_MagArgtoPrincipalzwei reelle Vektoren, Mag und Arg, zu einem polar-komplexen Vektor zusammenfassen und die Zeigerwinkel auf den Hauptwert normieren: -p < Arg ≤ +p
VF_MagtoPMag-Teil eines polar-komplexen Vektors überschreiben
VF_ArgtoPArg-Teil eines polar-komplexen Vektors überschreiben
VF_ReImtoPPolar-komplexen Vektor aus cartesischen Koordinaten konstruieren, die als getrennte Vektoren Re und Im vorliegen

Zurück zum Inhaltsverzeichnis

4.2 Index-orientierte Manipulationen

VF_revkehrt die Reihenfolge aller Elemente eines Vektor um (engl. to reverse = umkehren)
VCF_revconjkomplex-konjugierte Form in umgekehrter Element-Reihenfolge
VF_reflectreflektiert einen Vektor an seinem Mittelpunkt, so daß die obere Hälfte gleich der umgekehrten unteren Hälfte wird
VF_rotaterotiert einen Vektor um eine als Parameter übergebene Anzahl von Positionen (wobei auf einer Seite hinausgeschobene Elemente an der anderen wieder hineingeschoben werden)
VF_rotate_bufEffiziente Rotation eines Vektors unter Verwendung von benutzerspezifiziertem Pufferspeicher
VF_insertElement einfügen
VF_deleteElement entfernen
VF_sortSortieren (aufsteigende oder abfallende Folge)
VF_sortindmit einem Vektor assoziierten Index-Array sortieren
VF_subvectorUnter-Vektor aus einem (meist größeren) Vektor extrahieren mit konstantem Abtastintervall
VF_indpickfüllt einen Vektor mit Elementen eines anderen, wobei diese entsprechend ihren Indizes "herausgepickt" werden.
VF_indputverteilt die Elemente eines Vektors auf die durch ihre Indizes spezifizierten Plätze eines anderen Vektors.
 

Operationen, die nur auf eine Untermenge von Elementen (z.B. auf jedes vierte, zehnte o.ä.) angewandt werden sollen, werden durch die Funktionsfamilie VF_subvector_... zur Verfügung gestellt, wobei die drei Punkte für ein Suffix stehen, daß die jeweilige Operation bezeichnet:
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
 

Dem Durchsuchen von Tabellen nach bestimmten Werten dienen:
VF_searchC sucht das einem Wert C am nächsten kommende Element eines Vektors, wobei ein Parameter mode darüber entscheidet, ob das absolut nächste, das nächste "größere-oder-gleiche" oder das nächste "kleinere-oder-gleiche" gewählt werden
VF_searchVdasselbe für ein ganzes Feld von Suchwerten
 
An Interpolations-Routinen stellt OptiVec zur Verfügung:
VF_polyinterpolPolynom-Interpolation
VF_ratinterpolrationale Interpolation
VF_natCubSplineInterpol"natürliche" kubische Spline-Interpolation
VF_splineinterpolallgemeine kubische Spline-Interpolation
 

Zurück zum Inhaltsverzeichnis

4.3 Datentyp-Umwandlungen

Das erste, was über die nun folgenden Umwandlungsroutinen zu sagen wäre, ist, daß man sie möglichst selten anwenden sollte. Man überlege vorher, welche Genauigkeit und welchen Zahlenbereich man benötigt, und bleibe dann innerhalb dieser Genauigkeit. Da es aber doch immer wieder Gelegenheiten gibt, wo eine Umwandlung sich nicht umgehen läßt, ist für jeden Zweck die passende VectorLib-Funktion gegeben. Die folgende Tabelle faßt einige Beispiele zusammen. Die übrigen Funktionen dürfte sich von selbst ergeben:
V_FtoDfloat in double
V_CDtoCFcomplex<double> in complex<float> (mit Überlauf-Abfang)
V_PFtoPEpolar<float> in polar<extended>
VF_PtoCpolar<float> in complex<float>
V_ItoLIint in long int
V_ULtoUSunsigned long in unsigned short
V_ItoUsigned int in unsigned int. Die Umwandlungen zwischen vorzeichenbehafteten und vorzeichenlosen Typen beschränken sich allerdings auf Umwandlungen innerhalb der jeweils selben Genauigkeitsstufe. Funktionen wie "V_UStoLI" existieren naher nicht.
V_ItoFint to float
 
Die Umwandlung von Fließkomma- in ganze Zahlen wird durch die folgenden Funktionen bewerkstelligt, die sich in der Behandlung des Rundungsrestes unterscheiden:
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
 
Diese Operationen werden als mathematische Funktionen behandelt und in Kap. 4.6.1 beschrieben.

Zurück zum Inhaltsverzeichnis

4.4 Nähere Informationen zur Ganzzahl-Arithmetik

Im Zusammenhang mit der Arithmetik ganzer Zahlen (engl.: Integers) sollte man sich klar machen, daß alle Integer-Operationen implizit modulo 2n durchgeführt werden, wobei n die den jeweiligen Datentyp darstellende Anzahl von Bits ist. Jedes Ergebnis, das außerhalb des mit dem jeweiligen Typ darstellbaren Zahlenbereiches liegen würde, wird durch Verlust des oder der höchsten Bits auf den darstellbaren Bereich abgebildet. Im Ergebnis sieht das so aus, als wäre das Ergebnis durch Addition oder Subtraktion von soviel mal 2n wie nötig erhalten worden.

So wird man im Datentyp short / SmallInt als Ergebnis der Multiplikation 5 * 20000 die vielleicht unerwartete Zahl -31072 erhalten. Das "korrekte" Resultat, 100000, übersteigt den darstellbaren Bereich von short/SmallInt-Zahlen, -32768 ≤ x ≤ +32767. short / SmallInt sind 16-bit-Zahlen, also ist n = 16 und 2n = 65536. Man kann sich das Zustandekommen des erhaltenen Resultates also so vorstellen, als ob der Prozessor 2 * 65536 = 131072 von 100000 abgezogen hätte, was -31072 ergibt.

Überlaufende Zwischenergebnisse werden nicht durch nachfolgende Operationen "geheilt". Das Ergebnis der Berechnung von (5 * 20000) / 4 ist nicht – wie man vielleicht hoffen könnte – +25000, sondern -7768.

Zurück zum Inhaltsverzeichnis

4.5 Grundfunktionen komplexer Vektoren

Für die Behandlung cartesisch-komplexer Vektoren existieren die folgenden Grundfunktionen:
VF_ReImtoCBildung eines cartesisch-komplexen Vektors aus Real- und Imaginärteil
VF_RetoCÜberschreiben des Realteils
VF_ImtoCÜberschreiben des Imaginärteils
VF_CtoReImExtraktion von Real- und Imaginärteil
VF_CtoReExtraktion des Realteils
VF_CtoImExtraktion des Imaginärteils
VF_PolartoCBildung eines cartesisch-komplexen Vektors aus Polarkoordinaten, die als separate reelle Vektoren Mag und Arg vorliegen
VF_CtoPolarUmwandlung eines cartesisch-komplexen Vektors in Polarkoordinaten, die in separaten reellen Vektoren Mag und Arg abgelegt werden
VF_CtoAbsAbsolutwert (Zeigergröße in der komplexen Ebene)
VF_CtoArgArgument (Zeigerwinkel in der komplexen Ebene)
VF_CtoNormNorm (hier als Quadrat des Absolutwertes definiert)
VCF_normtoCNorm, gespeichert als komplexer Vektor (mit allen Imaginärteilen gleich 0)
 
Die entsprechenden Funktionen für Polarkoordinaten sind:
VF_MagArgtoPzwei reelle Vektoren, Mag und Arg, zu einem polar-komplexen Vektor zusammenfassen
VF_MagArgtoPrincipaldasselbe, mit Normierung der Zeigerwinkel auf den Hauptwert, -p < Arg ≤ +p
VF_MagtoPMag-Teil überschreiben
VF_ArgtoPArg-Teil überschreiben
VF_PtoMagArgMag- und Arg-Teile extrahieren
VF_PtoMagMag-Teil extrahieren
VF_PtoArgArg-Teil extrahieren
VF_PtoNormNorm (hier als Quadrat der Zeigerlänge definiert)
VF_ReImtoPpolar-komplexen Vektor aus cartesischen Koordinaten konstruieren, die als separate reelle Vektoren Re und Im vorliegen
VF_PtoReImpolar-komplexen-Vektor in cartesische Koordinaten umwandeln, die als zwei reelle Vektoren Re und Im gespeichert werden
VF_PtoReRealteil berechnen
VF_PtoImImaginärteil berechnen
VPF_principalHauptwert. Man erinnere sich, daß eine komplexe Zahl unendlich viele Darstellungen in Polarkoordinaten besitzt, deren Zeigerwinkel sich um ganzzahlige Vielfache von 2 p unterschieden. Die Darstellung mit -p < Arg ≤ +p wird Hauptwert genannt.
 

Zurück zum Inhaltsverzeichnis

4.6 Mathematische Funktionen

In Ermangelung einer besser begründeten Definition werden hier als "mathematisch" alle diejenigen Funktionen verstanden, bei denen jedes einzelne Element eines Vektors aus genau einem korrespondierenden Element eines anderen Vektors berechnet wird mit Hilfe einer mehr oder weniger einfachen Formel: Yi = f( Xi ) (im Unterschied also zu Funktionen wie der Fourier-Transformation, wo jedes Element des Ergebnis-Vektors von prinzipiell jedem Element des Eingabe-Vektors abhängt).

Mit Ausnahme der einfachen arithmetischen Funktionen (Addition, Subtraktion etc.), existieren die mathematischen Funktionen nur für die Fließkomma-Datentypen. Die meisten mathematischen Funktionen von VectorLib sind als vektorisierte Versionen der entsprechenden Funktionen von ANSI-C oder Pascal zu verstehen oder von diesen abgeleitet. In C/C++ werden Fehler grundsätzlich über die vom Compiler zur Verfügung gestellten (oder vom Anwender selbst geschriebenen) Funktionen _matherr und (bei Borland C++) _matherrl behandelt. In Pascal/Delphi bietet OptiVec dem Anwender die Möglichkeit, das Verhalten im Fehlerfall über die Funktion V_setFPErrorHandling festzulegen.
Zusätzlich zu dieser Fehlerbehandlung "pro Element" wird noch durch den Rückgabewert der Vektor-Funktion angegeben, ob die Berechnung für alle Elemente erfolgreich war oder ob irgendein Fehler auftrat. Im Falle fehlerfreier Verarbeitung ist der Rückgabewert FALSE (0), sonst TRUE (irgendeine Zahl ungleich 0).

Zurück zum Inhaltsverzeichnis

4.6.1 Rundung

Wie schon im Zusammenhang mit den Datentyp-Umwandlungsroutinen erwähnt, ist die Umwandlung von Fließkomma- in Ganzzahl-Typen nicht von vornherein eindeutig möglich. Man hat vielmehr die Behandlung der Stellen nach dem Komma näher zu spezifizieren. Das Resultat der Rundung wiederum kann entweder in dem ursprünglichen Fließkomma-Format belassen oder in einen der Ganzzahl-Typen umgewandelt werden. Die folgenden Funktionen belassen das Resultat als Fließkomma-Zahl:
VF_roundauf die nächstliegende ganze Zahl auf- oder abrunden
VF_chopNachkommastellen abschneiden (Rundung Richtung 0)
VF_truncidentisch mit VF_chop
VF_ceilaufrunden
VF_floorabrunden
 
Die folgenden Funktionen wandeln das Ergebnis in Ganzzahlen um (die Tabelle nennt die Funktionen für Umwandlung in den Typ int / Integer):
VF_roundtoIauf die nächstliegende ganze Zahl auf- oder abrunden
VF_choptoINachkommastellen abschneiden (Rundung Richtung 0)
VF_trunctoIidentisch mit VF_choptoI
VF_ceiltoIaufrunden
VF_floortoIabrunden
 
Selbstverständlich kann der Ziel-Datentyp auch jeder andere Ganzzahl-Typ sein. Einige wenige Beispiele sollten genügen:
VF_choptoSINachkommastellen abschneiden und als short / SmallInt speichern
VF_ceiltoLIaufrunden und als long / LongInt speichern
VF_floortoQIabrunden und als quad / QuadInt speichern
VF_roundtoUauf die nächstliegende ganze Zahl runden und als unsigned / UInt speichern
VF_ceiltoUSaufrunden und als unsigned short / USMall speichern
VD_choptoULNachkommastellen abschneiden und als unsigned long / ULong speichern

Zurück zum Inhaltsverzeichnis

4.6.2 Vergleiche

Viele numerische Aufgaben verlangen, Vektor-Elemente zu zählen oder zu selektieren, für die bestimmte Bedingungen erfüllt sind. Diese Bedingungen werden in Form von Vergleichen getestet. Zu diesem Zweck stellt OptiVec eine breite Palette von Vergleichs-Funktionen zur Verfügung. Jedes Element eines Vektors kann entweder mit 0, mit einem Sollwert C oder mit dem korrespondierenden Element eines anderen Vektors verglichen werden. Es gibt hierbei drei Möglichkeiten. Die erste besteht in der Unterscheidung der Fälle "kleiner als", "gleich" und "größer als". Das Ergebnis des Vergleiches wird in demselben Datentyp wie die Eingabe-Vektoren als Fließkomma-Zahlen −1.0 (für "kleiner als"), 0.0 (für "gleich") und +1.0 (für "größer als") angegeben. Beispiele sind die Funktionen
 
VF_cmp0Vergleich mit 0 (signum-Funktion)
VD_cmpCVergleich mit einem Sollwert C
VE_cmpVVergleich korrespondierender Vektorelemente

Die zweite Möglichkeit ist, dass –durch einen Unterstrich abgesetzt –die zu testende Bedingung angegeben wird. Das Resultat ist TRUE oder FALSE und wird als 1 oder 0, wieder in demselben Datentyp wie die Eingabe-Vektoren, gespeichert. Der Ergebnis-Vektor kann dann beispielsweise in Zeitreihen-Analyse-Aufgaben mit dem Eingabe-Vektor multipliziert werden, um nicht-konforme Eingabe-Elemente zu eliminieren. Beispiele sind:
 
VF_cmp_eq0  /  _eqC  /  _eqVXi =  0  /  C  /  Yi ?   (engl. "equal")
VF_cmp_ne0  /  _neC  /  _neVXi ≠ 0  /  C  /  Yi ?   (engl. "not equal")
VF_cmp_gt0  /  _gtC  /  _gtVXi > 0  /  C  /  Yi ?   (engl. "greater than")
VF_cmp_ge0  /  _geC  /  _geVXi ≥ 0  /  C  /  Yi ?   (engl. "greater or equal")
VF_cmp_lt0  /  _ltC  /  _ltVXi < 0  /  C  /  Yi ?   (engl. "less than")
VF_cmp_le0  /  _leC  /  _leVXi ≤ 0  /  C  /  Yi ?   (engl. "less or equal")
VF_cmp_stVXi ≈  Yi ?   (engl. "similar to")
VF_cmp_dtVXi ≉ Yi ?   (engl. "dissimilar to")

Als dritte Möglichkeit schießlich können die Indizes derjenigen Elemente in einem Index-Array abgelegt werden, für die die Bedingung als TRUE gefunden wurde, z.B.:
 
VF_cmp_neCindIndizes der Elemente Xi != C
VD_cmp_lt0indIndizes der Elemente Xi < 0
VE_cmp_geVindIndizes der Elemente Xi ≥ Yi

Während die eben beschriebenen einfachen Vergleichsfunktionen nur bezüglich einer einzigen Grenze testen, existieren einige Funktionen, die feststellen, ob Vektorelemente in einen durch zwei Grenzpunkte bestimmten Bereich fallen:
 
VF_cmp_inclrange0C TRUE für 0 ≤ x ≤ C (C positiv),
0 ≥ x ≥ C (C negativ)
VF_cmp_exclrange0C TRUE für 0 < x < C (C positiv),
0 > x > C (C negativ)
VF_cmp_inclrangeCC TRUE für CLo ≤ x ≤ CHi
VF_cmp_exclrangeCC TRUE für CLo < x < CHi
VF_cmp_inclrange0Cind Indizes der Elemente 0 ≤ Xi ≤ C  (C positiv)
oder  0 ≥ Xi > C  (C negativ)
VF_cmp_exclrange0Cind Indizes der Elemente 0 < Xi < C  (C positiv)
oder  0 > Xi > C  (C negativ)
VF_cmp_inclrangeCCind Indizes der Elemente CLo ≤ Xi ≤ CHi
VF_cmp_exclrangeCCind Indizes der Elemente CLo < Xi < CHi

Interessiert nicht das Ergebnis für jedes einzelne Vektor-Element, sondern nur die Anzahl der Elemente, so erhält man diese durch die Funktionen der VF_cnt_...-Familie ("cnt" kurz für engl. "to count" = "zählen"), z.B.:
VF_cnt_eq0Anzahl der Elemente Xi = 0
VF_cnt_gtCAnzahl der Elemente Xi > C
VF_cnt_inclrangeCCAnzahl der Elemente CLo ≤ Xi ≤ CHi
VF_cnt_leVAnzahl der Elemente Xi ≤ Yi
VF_cmp_ne0  /  _neC  /  _neVXi != 0  /  C  /  Yi ?   (engl. "not equal")

Um zu testen, ob sich in einer Tabelle bestimmte Werte finden, können die folgenden Funktionen benutzt werden:
VF_iselementC TRUE, wenn C ein Element der als Eingabevektor übergebenen Tabelle ist
VF_iselementV prüft für jedes Element von X, ob es in der Tabelle Tab enthalten ist

Zurück zum Inhaltsverzeichnis 

4.6.3 Direkte Bit-Manipulationen

Für die Ganzzahl-Datentypen steht eine Reihe von Bit-weisen Operationen zur Verfügung, die beispielsweise für schnelle Multiplikationen und Divisionen durch ganzzahlige Potenzen von 2 eingesetzt werden können:
VI_shlBits nach links schieben
VI_shrBits nach rechts schieben
VI_orOR-Operation mit Bit-Maske
VI_xorXOR-Operation mit Bit-Maske
VI_notalle Bits invertieren

Zurück zum Inhaltsverzeichnis

4.6.4 Arithmetische Grundfunktionen, Akkumulation

VectorLib stellt die im folgenden aufgeführten Arithmetik-Funktionen in vektorisierter Form zur Verfügung, wobei hier nur die VF_-Version explizit genannt wird. Die VD_- und VE_- Versionen existieren natürlich ebenfalls und – wo immer dies sinnvoll ist – auch komplexe und Ganzzahl-Versionen.
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

Neben diesen Grundfunktionen sind auch häufig gebrauchte Kombinationen von Addition und Division sowie die Pythagoras-Formel aufgenommen:
 
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²)

Die Funktionen in der rechten Kolumne der obigen beiden Abschnitte existieren zusätzlich noch in erweiterter Form. Diese wird durch durch das Präfix "VFx_" angegeben (das "x" stammt aus der englischen Bezeichnung "expanded"). Hier wird die jeweilige Funktion nicht für Xi selbst, sondern für (a * Xi + b) berechnet, z.B.
 
VFx_addV Zi = (a * Xi + b) + Yi
VFx_divrV Zi = Yi  /  (a * Xi + b)

Für die vier Grundrechenarten existiert noch eine weitere Spezialform, bei der das Ergebnis mit einem konstanten Faktor multipliziert wird. Diese "skalierte" Version wird durch den zusätzlichen Buchstaben "s" im Präfix angegeben:
 
VFs_addV Zi = C * (Xi + Yi)
VFs_subV Zi = C * (Xi - Yi)
VFs_mulV Zi = C * (Xi * Yi)
VFs_divV Zi = C * (Xi / Yi)

Unter den weiteren einfachen arithmetischen Operationen seien genannt:
 
VF_maxCsetzt Yi gleich Xi oder C, je nachdem, welcher von beiden Werten der größere ist
VF_minCwählt den kleineren Wert aus Xi und C
VF_maxVwählt den größeren Wert aus Xi und Yi und speichert ihn als Zi
VF_minVwählt den kleineren Wert aus Xi und Yi und speichert ihn als Zi
VF_limitführt eine Begrenzung des Zahlenbereiches durch
VF_flush0setzt alle Werte unterhalb eines als Parameter übergebenen Absolut-Schwellenwertes gleich 0
VF_flushInvberechnet das Inverse aller Werte oberhalb eines als Parameter übergebenen Absolut-Schwellenwertes und setzt das Ergebnis für alle anderen gleich 0
VF_absHugeersetzt negative Polstellen durch positive
VF_intfracspaltet Zahlen in ihre Ganzzahl- und Bruchzahl-Anteile auf
VF_mantexptrennt Zahlen in Mantisse und Exponent

Während allgemein alle OptiVec-Funktionen Ein- und Ausgabe-Vektoren desselben Datentyps verarbeiten, existieren die arithmetischen Funktionen auch für "gemischte" Operationen zwischen Fließkomma- und Ganzzahltypen, wobei das Ergenis stets in dem Fließkomma-Typ gespeichert wird, z.B.:
 
VF_addVIfVector Z = fVector X + iVector Y
VD_mulVULdVector Z = dVector X * ulVector Y
VE_divrVBIeVector Z = biVector Y / eVector X

In ähnlicher Weise existieren Funktionen für die Akkumulation von Daten in entweder demselben oder in höher-genauen Datentypen. Diese Funktionen entsprechen der Operation Y += X. Beispiele sind:
 
VF_accVfVector Y += fVector X
VD_accVFdVector Y += fVector X
VF_accVIfVector Y += iVector X
VQI_accVLIqiVector Y += liVector X

Innerhalb der Fließkomma-Datentypen besteht zusätzlich die Möglichkeit, gleich zwei Vektoren auf einmal zu akkumulieren:
VF_acc2VfVector Y += fVector X1 + fVector X2
VD_acc2VFdVector Y += fVector X1 + fVector X2

Ebenfalls nur innerhalb der Fließkomma-Datentypen existieren Funktionen zur Akkumulation von Quadraten und Produkten:
VF_accV2fVector Y += fVector X2
VD_accVF2dVector Y += fVector X2
VCF_accVmulVconjcfVector Y += cfVector X * cfVector Y*

Zurück zum Inhaltsverzeichnis 

4.6.5 Geometrische Vektor-Arithmetik

Im geometrischen Sinne ist ein Vektor ein Zeiger auf einen Punkt im n-dimensionalen Raum, wobei die Elemente des Vektors die Koordinaten dieses Punktes angeben. VectorLib enthält einige Funktionen, die sich auf diese Interpretation von Vektoren beziehen:
 
VF_scalprod Skalarprodukt zweier Vektoren
VF_xprod Vektor- oder Kreuzprodukt zweier Vektoren
VF_Euclid Euclid'sche Norm eines Vectors

Werden andererseits die Koordinaten mehrerer Punkte in einer Ebene entweder in zwei getrennten Vektoren X und Y oder in einem komplexen Vektor gespeichert, so existiert eine Funktion zur Rotation dieser Koordinaten:
VF_rotateCoordinates Rotation der durch zwei Vektoren X und Y angegebenen Koordinaten mehrer Punkte in einer Ebene gegen den Uhrzeigersinn; die neuen Koordinaten werden als Xrot und Yrot gespeichert.
VCF_rotateCoordinates Rotation der durch Real- und Imaginärteil des komplexen Vektors XY angegebenen Koordinaten mehrer Punkte in einer Ebene gegen den Uhrzeigersinn; die neuen Koordinaten werden als Real- und Imaginärteil des komplexen Vektors XYrot gespeichert.

Zurück zum Inhaltsverzeichnis 

4.6.6 Potenzen

Die folgenden Funktionen erheben Vektoren von Eingabedaten in bestimmte Potenzen. Während die "normalen" Versionen eine volle Fehlerbehandlung für optimale Sicherheit durchführen, können die schnellen "ungeschützten" Versionen in Situationen eingesetzt werden, wo man absolut sicher ist, daß alle Eingabe-Elemente gültige Ergebnisse liefern. Da die Abwesenheit von Fehlerprüfungen hier eine viel effizientere Vektorisierung erlaubt, sind diese Funktionen teilweise um ein Mehrfaches schneller als die geschützten Versionen. Man sei sich allerdings des Risikos bewußt: Ein eventueller Überlauf wird zum Absturz ohne Vorwarnung führen.
 
Normalversionungeschützte VersionOperation
VF_squareVFu_squareQuadrat
VF_cubicVFu_cubicKubik
VF_quarticVFu_quarticvierte Potenz
VF_rsquareVFu_rsquareReziprokes Quadrat
VF_rcubicVFu_rcubicReziprokes Kubik
VF_rquarticVFu_rquarticReziprokes der vierten Potenz
VF_sqrtVFu_sqrt Quadratwurzel (entspricht Potenz 0.5)
VF_rsqrt
VFu_rsqrt Reziproke Quadratwurzel (entspricht Potenz −0.5)
VF_ipowVFu_ipowbeliebige ganzzahlige Potenzen
VF_inv
VFu_inv Reziprok-Wert (entspricht Potenz −1)
VF_pown.a.beliebige reelle Potenzen
VF_powexpn.a.reelle Potenzen, multipliziert mit Exponentialfunktion: xrexp(x)
VF_polyVFu_polyPolynom
VF_polyOddVFu_polyOddnur aus ungeraden Termen bestehendes Polynom
VF_polyEvenVFu_polyEvennur aus geraden Termen bestehendes Polynom
VF_ratioVFu_ratioQuotient zweier Polynome
VF_ratioOddEvenVFu_ratioOddEvenQuotient zweier Polynome, wobei das Zähler-Polynom nur aus ungeraden Termen besteht und das Nenner-Polynom ausschließlich gerade Terme aufweist (wie z.B. bei der Darstellung der Tangens-Funktion als Quotient der Taylor-Reihen von Sinus und Cosinus)
VF_ratioEvenOddVFu_ratioEvenOddQuotient zweier Polynome, wobei das Zähler-Polynom nur aus geraden Termen besteht und das Nenner-Polynom ausschließlich ungerade Terme aufweist (wie z.B. bei der Darstellung der Cotangens-Funktion)
 

Während bei allen eben genannten Funktionen spezifizierte Potenzen beliebiger Zahlen erhalten werden, ist es bei der nun folgenden Gruppe von Funktionen umgekehrt:
 
VF_pow10 reelle Potenzen von 10
VF_ipow10 ganzzahlige Potenzen von 10 (als Fließkomma-Zahlen gespeichert)
VF_pow2 reelle Potenzen von 2
VF_ipow2 ganzzahlige Potenzen von 2 (als Fließkomma-Zahlen gespeichert)
VF_exp Exponentialfunktion
VF_exp10 Exponentialfunktion zur Basis 10 (identisch mit VF_pow10)
VF_exp2 Exponentialfunktion zur Basis 10 (identisch mit VF_pow2)
VF_expArbBase Exponentialfunktion zu beliebiger Basis
 
Alle diese Funktionen existieren auch in der erweiterten "VFx_"-Form, wie z.B.
VFx_square: Yi = (a * Xi + b)² 
Die erweiterte Form der ungeschützten Funktionen hat das Präfix VFux_.

Die äquivalenten Funktionen für komplex-zahlige Vektoren sind ebenfalls vorhanden, sowohl für cartesische als auch in Polarkoordinaten. Zusätzlich werden zwei Spezialfälle behandelt:
 
VCF_powReExpo reelle Potenzen komplexer Zahlen
VCF_exptoP übernimmt einen cartesischen Eingabevektor und gibt dessen Exponentialfunktion in Polarkoordinaten zurück

Zurück zum Inhaltsverzeichnis 

4.6.7 Exponential- und Hyperbel-Funktionen

Eine ganze Gruppe von Funktionen läßt sich auf die Exponentialfunktion zurückführen, aus der sie durch verschiedene einfache Operationen gewonnen wird.
 
VF_exp Exponentialfunktion
VF_expc komplementäre Exponentialfunktion Yi = 1 - exp[ Xi ]
VF_expmx2 Exponentialfunktion des negativen Quadrates des Arguments: Yi = exp[ - X2i ].
Dies ist eine glockenförmige Funktion ähnlich der Gauss-Funktion
VF_Gauss Gauss'sche Verteilungsfunktion
VF_erf Gauss'sches Fehlerintegral
VF_erfc Komplement des Gauss'schen Fehlerintegrals, 1 - erf( Xi )
VF_powexpreelle Potenzen, multipliziert mit Exponentialfunktion, Xirexp(Xi)
 
Die vektorisierten Formen der Hyperbel-Funktionen werden zur Verfügung gestellt durch:
VF_sinh Hyperbel-Sinus
VF_cosh Hyperbel-Cosinus
VF_tanh Hyperbel-Tangens
VF_coth Hyperbel-Cotangens
VF_sech Hyperbel-Secans
VF_cosech Hyperbel-Cosecans
VF_sech2 Quadrat des Hyperbel-Secans

Zurück zum Inhaltsverzeichnis 

4.6.8 Logarithmen

VF_log10 dekadischer Logarithmus (zur Basis 10)
VF_log natürlicher Logarithmus (zur Basis e)
VF_ln Synonym für VF_log
VF_log2 binärer Logarithmus (zur Basis 2)
 
Auch hier existieren die cartesisch-komplexen Versionen. Die polar-komplexen Versionen stellen aber insofern eine Besonderheit dar, als sie das Ergebnis stets in cartesischen Koordinaten zurückgeben:
VPF_log10toC dekadischer Logarithmus (zur Basis 10)
VPF_logtoC natürlicher Logarithmus (zur Basis e)
VPF_lntoC Synonym für VPF_logtoC
VPF_log2toC binärer Logarithmus (zur Basis 2)

Als Sonderform des Zehner-Logarithmus ist die Formel für die Optische Dichte, OD = log10( X0/X ) anzusehen. Aufgrund ihrer Bedeutung in der experimentellen naturwissenschaftlichen Arbeit ist sie hier in mehreren Varianten aufgenommen, von denen einige Beispiele in der folgenden Tabelle zusammengefaßt sind: 
VF_ODOD = log10( X0/X ) für fVector als Eingabe und als Ausgabe
VF_ODwDarkOptische Dichte mit Dunkelstrom-Korrektur:
OD = log10( (X0−X0Dark) / (X−XDark) ) für fVector als Eingabe und als Ausgabe
VUS_ODtoFOD in float / Single-Genauigkeit für usVector als Eingabe
VUL_ODtoDOD in double-Genauigkeit für ulVector als Eingabe
VQI_ODtoEwDarkOD mit Dunkelstrom-Korrektur in extended-Genauigkeit für qiVector als Eingabe

Zurück zum Inhaltsverzeichnis 

4.6.9 Trigonometrische Funktionen

Einige der trigonometrischen Funktionen existieren in zwei Varianten. Die erste Variante folgt den üblichen Regeln der Fehlerbehandlung mathematischer Funktionen. Die zweite Variante ist für Situationen, in denen man mit Sicherheit weiß, daß alle Eingabewerte in den Bereich -2p ≤ Xi ≤ +2p fallen. Diese "Funktionen mit reduziertem Eingabe-Bereich" arbeiten deutlich schneller als die Normalvariante. Sie werden allerdings ohne Vorwarnung abstürzen, falls sich doch ein Eingabewert außerhalb des genannten Bereiches befindet. Da alle übrigen trigonometrischen Funktionen selbst für Argumente innerhalb dieses Bereiches ohnehin eine Bereichsprüfung und Fehlerbehandlung durchführen müssen, existieren die Varianten mit reduziertem Eingabe-Bereich derzeit nur für den Sinus und den Cosinus.
 
VF_sinSinus
VFr_sinschnelle Sinus-Funktion für den reduzierten Eingabe-Bereich -2p ≤ Xi ≤ +2p
VF_cosCosinus
VFr_cosschnelle Cosinus-Funktion für -2p ≤ Xi ≤ +2p
VF_sincosgleichzeitige Berechnung von Sinus und Cosinus
VFr_sincosSinus und Cosinus für -2p ≤ Xi ≤ +2p
VF_tanTangens
VF_cotCotangens
VF_secSecans
VF_cosecCosecans

Die Quadrate der trigonometrischen Funktionen werden gebildet durch:
 
VF_sin2Sinus²
VFr_sin2Sinus² für -2p ≤ Xi ≤ +2p
VF_cos2Cosinus²
VFr_cos2Cosinus² für -2p ≤ Xi ≤ +2p
VF_sincos2Sinus² und Cosinus² gleichzeitig
VFr_sincos2Sinus² und Cosinus² für -2p ≤ Xi ≤ +2p
VF_tan2Tangens²
VF_cot2Cotangens²
VF_sec2Secans²
VF_cosec2Cosecans²
 
Ein sehr effizienter Weg zur Berechnung trigonometrischer Funktionen für Argumente, die sich als gebrochenzahlige Vielfache von p (PI) darstellen lassen, wird durch die Funktionen mit dem Suffix "rpi" (für "rationale Vielfache von p") bereitgestellt. Hier ist r = p / q, wobei q konstant und p durch die Eingabevektor-Elemente gegeben ist:
 
VF_sinrpiSinus von p/q * p
VF_cosrpiCosinus von p/q * p
VF_sincosrpiSinus und Cosinus von p/q * p at once
VF_tanrpiTangens von p/q * p
VF_cotrpiCotangens von p/q * p
VF_secrpiSecans von p/q * p
VF_cosecrpiCosecans von p/q * p

Spezialisierte Versionen gebrauchen Tabellen, um häufig vorkommende Werte direkt zu lesen, anstatt sie berechnen zu müssen. Die werden durch die Suffixe "rpi2" (Vielfache von p dividiert durch eine ganzzahlige Potenz von 2) und "rpi3" (Vielfache von p dividiert durch ein ganzzahliges Vielfaches von 3) bezeichnet. Beispiele sind:
 
VF_sinrpi2 Sinus von p / 2n * p
VF_tanrpi3 Tangens von p / (3*n) * p

Zwei spezielle trigonometrische Funktionen sind: 
VF_sinc Sinc-Funktion, Yi = sin( Xi ) / Xi
VF_Kepler Kepler-Funktion (zeitabhängige Winkelposition eines Himmelskörpers nach dem Zweiten Keplerschen Gesetz bei gegebener Umlaufzeit und Exzentrizität)

Vektorisierte inverse trigonometrische Funktionen (die "Arcus"-Funktionen) stehen zur Verfügung als: 
VF_asinArcus-Sinus
VF_acosArcus-Cosinus
VF_atanArcus-Tangens
VF_atan2 Arcus-Tangens von Quotienten, Zi = atan( Yi / Xi )

Zurück zum Inhaltsverzeichnis 

4.7 Analysis

Es gibt eine ganze Reihe von Funktionen zur Bestimmung analytischer Eigenschaften von Datensätzen:
 
VF_derivV Ableitung eines Y-Arrays nach einem X-Array
VF_derivC desgleichen für konstante Intervalle zwischen den X-Werten
VF_integralV Wert des Integrals eines Y-Arrays über einem X-Array
VF_runintegralV Punkt-für-Punkt-Integral ("laufendes" Integral)
VF_integralC Integral über einer X-Achse mit konstantem Punktabstand
VF_runintegralC Punkt-für-Punkt-Integral über einer X-Achse mit konstantem Punktabstand
VF_ismonoton Test, ob sich die Elemente eines Vektors in monoton steigender oder fallender Anordnung befinden
VF_iselementC Test, ob ein gegebener Wert in einem Vektor auftaucht
VF_searchC Bestimmung des einem vorgegebenen Wert C am nächsten kommenden Eintrages in einer Tabelle
VF_localmaxima Detektion lokaler Maxima (Punkte, deren rechter und linker Nachbar kleiner sind)
VF_localminima Detektion lokaler Minima (Punkte, deren rechter und linker Nachbar größer sind)
VF_max globales Maximum
VF_min globales Minimum
VF_minmax globales Minimum und Maximum
VF_maxind globales Maximum und sein Index
VF_minind globales Minimum und sein Index
VF_absmax globales Absolutwert-Maximum
VF_absmin globales Absolutwert-Minimum
VF_absminmax globales Absolutwert-Minimum und -Maximum
VF_minpos kleinster positiver Wert innerhalb eines Vektors
VF_absmaxind global größter Absolutwert und sein Index
VF_absminind global kleinster Absolutwert und sein Index
VF_maxexp global größter Exponent
VF_minexp global kleinster Exponent
VF_runmax "laufendes" Maximum
VF_runmin "laufendes" Minimum

Die komplexen Äquivalente der zuletzt genannten Gruppe von Funktionen sind:
 
VCF_maxReIm größter Real- und größter Imaginärteil einzeln
VCF_minReIm kleinster Real- und kleinster Imaginärteil einzeln
VCF_absmaxReIm betragsmäßig größter Real- und Imaginärteil einzeln
VCF_absminReIm betragsmäßig kleinster Real- und Imaginärteil einzeln
VCF_absmax größter Absolutwert (Zeigerlänge; dies ist eine reelle Zahl)
VCF_absmin kleinster Absolutwert (Zeigerlänge)
VCF_cabsmax komplexe Zahl mit dem größten Absolutwert
VCF_cabsmin komplexe Zahl mit dem kleinsten Absolutwert
VCF_sabsmax komplexe Zahl mit der größten Summe |Re| + |Im|
VCF_sabsmin komplexe Zahl mit der kleinsten Summe |Re| + |Im|
VCF_absmaxind größter Absolutwert und sein Index
VCF_absminind kleinster Absolutwert und sein Index

Summen, Produkte usw. werden durch die in chapter 4.9 als Statistik-Funktionen zusammengefaßten Routinen gebildet.

Zur Berechnung des Schwerpunktes eines Vektors stehen zwei Funktionen zur Verfügung:
 
VF_centerOfGravityIndSchwerpunkt eines Vektors in Form eines interpolierten Element-Indexes
VF_centerOfGravityVSchwerpunkt eines Y-Vektors bei explizit gegebener X-Achse

Zurück zum Inhaltsverzeichnis 

4.8 Signalverarbeitung:
Fourier-Transformations-Techniken

Die folgenden Funktionen dienen der Signalverarbeitung mittels Fourier-Transformation:
 
VF_FFTtoC Schnelle Fourier-Transformation (FFT) eines reellen Vektors; das Ergebnis ist ein cartesisch-komplexer Vektor
VF_FFT Vorwärts- und Rückwärts-FFT reeller Vektoren; das Ergebnis der Vorwärts-Transformation ist ein gepackt-komplexer Vektor derselben Speicher-Größe wie der Eingabevektor.
VCF_FFT Vorwärts- und Rückwärts-FFT komplexer Vektoren
MF_Rows_FFTFFT entlang der Zeilen einer Matrix; diese Funktion kann zur Batch-Verarbeitung mehrer Vektoren gleicher Größe verwendet werden, die hierfür als Zeilen einer Matrix gespeichert werden müssen
MF_Cols_FFTFFT entlang der Spalten einer Matrix; diese Funktion kann zur Batch-Verarbeitung mehrer Vektoren gleicher Größe verwendet werden, die hierfür als Spalten einer Matrix gespeichert werden müssen
VF_convolve
VF_convolvewEdit
Faltung mit einer gegebenen Impulsantwortfunktion
VF_deconvolve
VF_deconvolvewEdit
Entfaltung unter Annahme einer gegebenen Impulsantwortfunktion
VF_filter spektrale Filterung
VF_spectrum spektrale Analyse
VF_xspectrum Kreuz-Leistungsspektrum zweier Signale (komplexe Version)
VF_xspectrumAbs Kreuz-Leistungsspektrum zweier Signale (Absolutwert)
VF_coherence Kohärenzfunktion zweier Signale
VF_autocorr Autokorrelationsfunktion eines Datensatzes
VF_xcorr Kreuzkorrelationsfunktion zweier Datensätze
VF_setRspEdit Standard-Editierschwelle für den intermediär bei Faltungen und Entfaltungen berechneten Filter setzen (entscheidet über die Behandlung "verlorener" Frequenzen)
VF_getRspEdit derzeit eingestellte Standard-Editierschwelle lesen

Alle genannten Funktionen benötigen intern zusätzlichen Pufferspeicher, den sie selbst allozieren und wieder freigeben. Um diese Ineffizienz bei wiederholten Aufrufen umgehen zu können, existiert von allen diesen Funktionen eine durch das Präfix VFb_ gekennzeichnete Version, die einen Zeiger auf vom Aufrufer zur Verfügung gestellten Pufferspeicher als zusätzliches Argument übernimmt. Die notwendige Mindestgröße des Pufferspeichers ist in FUNKREF.HTM für jede Funktion einzeln angegeben.

Obwohl sie keine Fourier-Transformation benutzen, sollen in diesem Zusammenhang die Funktionen VF_biquad für bi-quadratische Audio-Filterung sowie VF_smooth (engl. to smooth = glätten) als einer etwas groben Form der Frequenzfilterung genannt werden.

Zurück zum Inhaltsverzeichnis 

4.9 Statistische Funktionen und Bausteine

OptiVec bietet die folgende Kollektion von Statistik-Funktionen:
 
VF_sum Summe aller Elemente
VI_fsum Summe aller Elemente eines Ganzzahl-Vektors, die als Fließkommazahl in double- oder extended- Genauigkeit akkumuliert wird
VF_prod Produkt aller Elemente
VF_ssq Quadratsumme aller Elemente
VF_sumabs Summe der Absolutwerte aller Elemente
VF_rms Wurzel des mittleren Quadrats aller Elemente
VF_runsum laufende Summe
VF_runprod laufendes Produkt
VF_sumdevC Summe der Abweichungen von einem Sollwert, Summe( |Xi-C| )
VF_sumdevV Summe der Abweichungen von einem anderen Vektor, Summe( |Xi-Yi| )
VF_sumdevVwSaturation Summe der Abweichungen von einem anderen Vektor, Summe( |Xi-Yi| ) mit Begrenzung eventuellen Überlaufs auf HUGE_VAL
VF_subV_sumabs Differenz zweier Vektoren und Summe über die Absolutwerte der einzelnen Abweichungen
VF_avdevC mittlere Abweichung von einem Sollwert, 1/N * Summe( |Xi-C| )
VF_avdevV mittlere Abweichung von einem anderen Vektor, 1/N * Summe( |Xi-Yi| )
VF_ssqdevC Quadratsumme der Abweichungen von einem Sollwert,
Summe( (Xi - C)² )
VF_ssqdevV Quadratsumme der Abweichungen von einem anderen Vektor,
Summe( (Xi - Yi)² )
VF_ssqdevVwSaturation Quadratsumme der Abweichungen von einem anderen Vektor,
Summe( (Xi - Yi)² ) mit Begrenzung eventuellen Überlaufs auf HUGE_VAL
VF_subV_ssq Differenz zweier Vektoren und Quadratsumme über die einzelnen Abweichungen
VF_chi2 Chi-Quadrat-Testwert
VF_chi2wSaturation Chi-Quadrat-Testwert mit Begrenzung eventuellen Überlaufs auf HUGE_VAL
VF_subV_chi2 Differenz zweier Vektoren und Chi-Quadrat-Testwert
VF_chiabs "robuster" Testwert ähnlich VF_chi2, aber auf absoluten statt auf quadratischen Abweichungen basierend
VF_chiabswSaturation wie VF_chiabs, aber mit Begrenzung eventuellen Überlaufs auf HUGE_VAL
VF_subV_chiabs Differenz zweier Vektoren und chiabs-Testwert
VF_mean gleichgewichtetes Mittel (Durchschnitt) aller Elemente
VF_meanwW gewichtetes Mittel
VF_meanabs gleichgewichtetes Mittel aller Absolutwerte
VF_selected_mean Mittel über diejenigen Vektorelemente, die in einen bestimmten Wertebereich fallen; hierdurch lassen sich Ausreißerpunkte von der Mittelwertbildung ausschließen
VF_varianceC Varianz einer Verteilung bezüglich eines Sollwertes
VF_varianceCwW desgl. mit Einzelpunkt-Wichtung
VF_varianceV Varianz einer Verteilung bezüglich einer zweiten
VF_varianceVwW desgl. mit Einzelpunkt-Wichtung
VF_meanvar Mittelwert und Varianz einer Verteilung
VF_meanvarwW desgl. mit Einzelpunkt-Wichtung
VF_median Median einer Verteilung
VF_corrcoeff linearer Korrelationskoeffizient zweier Verteilungen
VF_distribution Histogramm (diskrete eindimensionale Verteilungsfunktion einer eindimensionalen Verteilung)
VF_min_max_mean_stddev gleichzeitige Berechnung von Minimum, Maximum, Mittelwert und Standardabweichung einer eindimensionalen Verteilung

Zurück zum Inhaltsverzeichnis 

4.10 Datenanpassung

Von linearer Regression bis hin zu komplexen Anpassungsproblemen mit mehreren Datensätzen und nichtlinearen Modellfunktionen mit vielen freien Parametern bietet OptiVec eine breite Palette von Routinen für fast alle praktisch vorkommenden Datenanpassungs-Aufgaben. Da sie alle, mit Ausnahme der einfachen linearen Regression, auf Matrix-Methoden basieren, gehören sie zu MatrixLib. Dies bedeutet, dass man die Include-Dateien <MFstd.h> (<MDstd.h>< MEstd.h>) oder die Units MFstd, (MDstd, MEstd) einschließen muss, um sie benutzen zu können.

Eine detaillierte Beschreibung der verschiedenen Konzepte zur Datenanpassung an die unterschiedlichen Klassen von Modellfunktionen wird in Kap. 13 von MATRIXD.HTM gegeben. Daher genüge an dieser Stelle eine tabellarische Zusammenfassung der vorhandenen X-Y-Anpassungsroutinen:
 
VF_linregress lineare Regression von X-Y-Daten mit gleicher Wichtung aller Datenpunkte
VF_linregresswW dasselbe mit ungleicher Wichtung
VF_polyfit Koeffizienten eines Polynoms an vorhandene X-Y-Daten anpassen
VF_polyfitwW dasselbe mit ungleicher Wichtung der Datenpunkte
VF_polyfitOdd Koeffizienten eines nur aus ungeraden Termen bestehenden Polynoms an vorhandene X-Y-Daten anpassen
VF_polyfitOddwW dasselbe mit ungleicher Wichtung der Datenpunkte
VF_polyfitEven Koeffizienten eines nur aus geraden Termen bestehenden Polynoms an vorhandene X-Y-Daten anpassen
VF_polyfitEvenwW dasselbe mit ungleicher Wichtung der Datenpunkte
VF_linfit Koeffizienten einer beliebigen, in ihren Parametern linearen Funktion an vorhandene X-Y-Daten anpassen
VF_linfitwW dasselbe mit ungleicher Wichtung der Datenpunkte
VF_nonlinfit Koeffizienten einer beliebigen, möglicherweise nicht-linearen Funktion an vorhandene X-Y-Daten anpassen
VF_nonlinfitwW dasselbe mit ungleicher Wichtung der Datenpunkte
VF_multiLinfit mehrere X-Y-Datensätze gleichzeitig an eine gemeinsame lineare Funktion anpassen
VF_multiLinfitwW dasselbe mit ungleicher Wichtung der Datenpunkte
VF_multiNonlinfit mehrere X-Y-Datensätze gleichzeitig an eine gemeinsame nicht-lineare Funktion anpassen
VF_multiNonlinfitwW dasselbe mit ungleicher Wichtung der Datenpunkte

Zurück zum Inhaltsverzeichnis 

4.11 Input und Output

VF_cprint Windows mit MS Visual C++ oder Borland / Embarcadero Compiler:/u> Ausdruck der Elemente eines Vektors auf dem Bildschirm (der "Konsole"; daher das "c" im Namen) im aktuellen Textfenster, wobei die Seiten umgebrochen werden. Höhe und Breite dieses Fensters werden automatisch detektiert. Nur für Konsolen-Anwendungen.
Andere Windows-Compiler sowie Linux: identisch mit VF_print.
VF_print ähnlich VF_cprint; auch hier erfolgt die Ausgabe auf dem Bildschirm, aber ohne automatische Detektion der Bildschirmdaten. Die angenommene Standardbreite wird durch die symbolische Konstante V_consoleWindowWidth angegeben (definiert in <VecLib.h> bzw. in der Unit VecLib als 150). Ein Seitenumbruch findet nicht statt (d.h. alle Seiten laufen durch, bis die letzte schließlich stehenbleibt). (Nur Konsolen-Anwendungen)
VF_fprint Ausgabe eines Vektors in einen Stream
VF_chexprint ähnlich VF_cprint, aber Ausgabe im Hexadezimal-Format.
VF_hexprint ähnlich VF_print, aber Ausgabe im Hexadezimal-Format.
VF_fhexprint ähnlich VF_fprint, aber Ausgabe im Hexadezimal-Format.
VF_write Ablage von Daten im ASCII-Format auf Festplatte
VF_read liest einen Vektor aus einer ASCII-Datei ein
VF_nwrite schreibt n gleichartige Vektoren als Spalten einer Tabelle in eine ASCII-Datei
VF_nread liest die Spalten einer Tabelle in n gleichartige Vektoren ein
VF_store Speichern im Binärformat
VF_recall Einlesen im Binärformat

Die folgenden Funktionen modifizieren die Standardeinstellung für VF_write,   VF_nwrite und VI_read:
 
VF_setWriteFormat bestimmtes Ausgabeformat vorgeben
VF_setWriteSeparate Trennzeichen zwischen aufeinander folgenden Element für VF_write vorgeben
VF_setNWriteSeparate Trennzeichen zwischen den durch VF_nwrite geschriebenen Spalten definieren
V_setRadix für die ganzzahligen V.._read-Funktionen eine andere als die als Standard angenommene Basis 10 einstellen.

Zurück zum Inhaltsverzeichnis 

4.12 Graphik

VectorLib bietet eine Reihe von Funktionen zum Plotten von in Arrays vorliegenden Daten. Bevor eine der eigentlichen Plot-Funktionen aufgerufen werden kann, müssen die Graphik-Funktionen von VectorLib initialisiert werden:
 
V_initPlot Graphikfunktionen von VectorLib initialisieren. Es ist nicht nötig, nach Gebrauch einen Abschluss durchzuführen, da V_initPlot nur Zahlenwerte initialisiert, aber keine Speicherreservierungen o.ä. durchführt und die Windows-Graphikfunktionen stets vorhanden bleiben. V_initPlot reserviert automatisch einen Bildschirmausschnitt für Plot-Operationen, der etwa die rechten 2/3 des Bildschirms umfaßt und oben noch Raum für eine Überschrift sowie unten ein paar Zeilen für eine Unterschrift freilässt. Am unteren Rand bleiben einige Zeilen frei. Um die Standard-Einstellung zu ändern, rufe man V_setPlotRegion nach V_initPlot.
V_initPrint Graphikfunktionen von VectorLib initialisieren und die Ausgabe auf einen Drucker umleiten. Standardmäßig wird eine ganze Seite zum Druck verwandt. Auch diese Einstellung läßt sich mit Hilfe von V_setPlotRegion nach V_initPrint ändern.
V_setPlotRegion Definition eines von der automatischen Wahl abweichenden Fensterausschnitts

VectorLib unterscheidet zwei Arten von Plot-Funktionen: AutoPlot und DataPlot. Alle AutoPlot-Funktionen (z.B. VF_xyAutoPlot) führen die folgenden Schritte durch:

  1. Definition eines geeigneten Viewports innerhalb des standardmäßig eingestellten oder mittels V_setPlotRegion gewählten Fensterausschnitts
  2. Löschen des vorhandenen Viewport-Inhalts
  3. Erzeugung eines cartesischen Koordinatensystems mit geeigneter Achsenskalierung
  4. Unterteilung und Beschriftung der Achsen entweder linear oder logarithmisch, entsprechend dem Suffix der gewählten AutoPlot-Funktion:
    V?_autoPlot (kein Suffix): sowohl X-Achse als auch Y-Achse linear.
    V?_autoPlot_xlg_ylin: X-Achse logarithmisch, Y-Achse linear.
    V?_autoPlot_xlg_ylg: sowohl X-Achse also auch Y-Achse logarithmisch.
    V?_autoPlot_xlin_ylg: X-Achse linear, Y-Achse logarithmisch.
  5. Auftragung der Daten gemäß den an die jeweilige Funktion übergebenen Parametern
Alle DataPlot-Funktionen führen lediglich den letzten dieser Schritte durch, d.h. sie gehen davon aus, dass ein Koordinatensystem bereits existiert, und zwar von einem Aufruf einer AutoPlot-Funktion, von V_findAxes, oder von V_drawAxes. In dieses Koordinatensystem erfolgt die gewünschte Auftragung. Alle Einstellungen des Koordinatensystems müssen hierfür noch gültig sein. Es darf also nicht inzwischen ein anderer Viewport definiert worden sein, und die Skalierung der Achsen muss auch für die hinzukommende Auftragung "passen".
Um Text und andere Beschriftungen hinzuzufügen, sollte ein neuer Viewport definiert werden durch Aufruf der Windows-Funktion SetViewportOrgEx. Andernfalls werden alle Positionsangaben von der linken oberen Ecke des gezeichneten Koordinatensystems aus gerechnet.
Die verschiedenen Darstellungs-Optionen (Symbole, Linien und Farben) werden als Parameter beim Aufruf der jeweiligen Funktion spezifiziert, siehe VF_xyAutoPlot. Hier folgt eine Liste der vorhandenen AutoPlot- und DataPlot-Routinen:
 
VF_xyAutoPlot automatisch skalierter Plot eines X-Y-Vektor-Paares
VF_yAutoPlot automatisch skalierter Plot eines Y-Vektors gegen den als X-Achse verwendeten Element-Index
VF_xy2AutoPlot gleichzeitige Auftragung zweier X-Y-Paare, wobei die Achsenskalierung sicherstellt, dass beide in dasselbe Koordinatensystem passen
VF_y2AutoPlot desgl. für zwei gegen ihre Indizes aufgetragene Y-Vektoren
VF_xyDataPlot zusätzlichen X-Y-Datensatz auftragen
VF_yDataPlot zusätzlichen Y-Vektor gegen seinen Index auftragen

Vektoren aus cartesisch-komplexen Zahlen werden in der komplexen Ebene dargestellt, d.h. die Imaginärteile gegen die Realteile aufgetragen. Hierzu dienen
 
VCF_autoPlot Auftragung eines cartesisch-komplexen Vektors
VCF_2AutoPlot gleichzeitige Auftragung zweier komplexer Vektoren
VCF_dataPlot Hinzufügung eines weiteren komplexen Vektors zu einer bestehenden Auftragung

Funktionen zur Auftragung polar-komplexer Vektoren sind derzeit nicht enthalten.
Es ist möglich, mehrere Koordinatensysteme in ein-und-dasselbe Fenster zu zeichnen. Die Position jedes Koordinatensystems muss über die oben erwähnte Funktion V_setPlotRegion spezifiziert werden. Dem Umschalten zwischen ver- schiedenen Koordinatensystemen (z.B. um neue DataPlots hinzuzufügen) dienen die folgenden Funktionen:
 
V_continuePlot Wiederherstellung des zuletzt für einen Plot verwendeten Viewports und der zugehörigen Achsen-Skalierungen
V_getCoordSystem Speichern der Position und Skalierungen eines Koordinatensystems
V_setCoordSystem Wiederherstellung von Position und Skalierungen eines Koordinatensystems. Diese müssen zuvor mittels V_getCoordSystem gespeichert worden sein.

Zurück zum Inhaltsverzeichnis 


5. Fehlerbehandlung

5.1 Allgemeines

Es gibt grundsätzlich zwei Arten von Fehlerbehandlung: Durch die Hardware oder durch die Software. Um einen unkontrollierten Absturz zu vermeiden, ist es immer wünschenswert, drohende Fehler durch die Software abzufangen, bevor sie Unheil anrichten können. Alle Hochsprachen unterstützen diese Software-Fehlerbehandlung bis zu einem gewissen Grad an Perfektion. Innerhalb der sehr strikt definierten OptiVec-Funktionen lässt sich häufig eine noch effizientere Fehlerbehandlung durchführen als sie einem Compiler für "normalen" Programmcode möglich ist.

Die Produktions-Bibliotheken von OptiVec behandeln alle mathematischen Fehler (Überlauf, Singularitäten, Bereichsfehler, Genauigkeits-Verlust) "stillschweigend" und setzen die Programmausführung mit einem wenn möglich in den darstellbaren Bereich hinein korrigierten Ergebnis fort.
Die Debug-Bibliotheken zeigen Fehler zusätzlich durch Ausgabe einer Meldung an. Wie unten noch näher erklärt, kann mit Hilfe der Funktion V_setFPErrorHandling eingestellt werden, welche Fehler tatsächlich gemeldet werden. Die Funktion V_setErrorEventFile wiederum erlaubt die Auswahl zwischen Meldungs-Ausgabe in eine Datei, ein Popup-Window oder ein Text-Fenster.
Eine Folge identischer Fehler innerhalb ein- und derselben OptiVec-Funktion führt immer nur zu einer einzigen Meldung. Nachfolgende identische Meldungen werden unterdrückt.

Dem Abfangen und Behandeln von Fehlern sind allerdings Grenzen gesetzt, insbesondere für den Überlauf-Schutz innerhalb der extended-, teilweise auch der double-Versionen von OptiVec-Funktionen. Der Programmierer sollte generell darauf achten, dass konstante Paramater bei der Übergabe an Funktionen sicherheitshalber nicht größer als 1.E32 für float / Single, 1.E150 für double und 1.E2000 für extended sind.

In den "erweiterten" Versionen aller extended-genauen Funktionen (also denen mit den Präfixen VEx_ und VCEx_; z.B. VEx_exp) wird generell kein Überlauf-Schutz für die Berechnung des Zwischenergebnisses A*Xi+B gewährt, sondern nur für den Kern der Funktion selbst und für die abschließende Multiplikation mit dem Skalierungsfaktor C.

Zwischen Fließkomma- und Ganzzahlen besteht ein grundsätzlicher Unterschied bezüglich OVERFLOW- und DOMAIN- Fehlern: Für Fließkommazahlen sind dies ernst zu nehmende (OVERFLOW) bzw. zur Unbrauchbarkeit des Ergebnisses führende (DOMAIN) Fehler. Demgegenüber wird für Ganzzahlen eine implizite modulo-2n-Arithmetik verwendet, bei der diese "Fehler" gar nicht als solche betrachtet werden. Im Gegenteil: Häufig wird sogar der Überlauf als schnelles Mittel der modulo-Division ausgenutzt. In den folgenden beiden Abschnitten wird die Fehlerbehandlung von Fließkomma- und Ganzzahlen detailliert dargestellt.

Zurück zum Inhaltsverzeichnis

5.2 Ganzzahl-Fehler

Die einzige Operation, die bei ganzen Zahlen immer ein Fehler ist, ist die Division durch 0, die zu einer ZERODIVIDE-Exception führt. Überlauf- und Bereichs-Fehler, also INTEGER OVERFLOW und INTEGER DOMAIN (letztere entstehen z.B. beim Zuweisen einer negativen Zahl zu einem vorzeichenlosen Typ), werden schlicht ignoriert bzw. im Sinne der erwähnten impliziten modulo-2n-Arithmetik um-interpretiert. Für Fälle, in denen dies nicht erwünscht ist, bietet die 32-bit-Version von VectorLib neben der Normalversion aller Integer-Funktionen eine weitere Version mit der Möglichkeit, diese Fehler abzufangen und eine Fehlermeldung auszugeben, gegebenenfalls auch das Programm abzubrechen.

Nur 32-bit-Versionen (also nicht für 64-bit):
Alle Funktionen, in denen INTEGER OVERFLOW (z.B. in VI_rampVI_mulV, etc.) oder INTEGER DOMAIN-Fehler (z.B. in V_ItoU für negative X-Werte) auftreten können, existieren in zwei Varianten: Die Normalversion wendet implizite modulo-2n-Arithmetik an und wandelt vorzeichenbehaftete und vorzeichenlose Typen gemäß ihrem Bitmuster ineinander um. Für die 16-bit- und 32-bit-Ganzzahltypen (nicht aber für 8-bit und 64-bit) gibt es eine zweite Version, die zwar auch modulo-2n-Arithmetik anwendet, Fehler aber detektiert. Diese zweite Variante wird durch den Buchstaben "o" (für "OVERFLOW-Detektion") im Präfix angegeben: VIo_,  VSIo_,  VULo_, usw. Für die Ganzzahl-Datentypumwandlungsfunktionen wird das Präfix V_ zu Vo_ erweitert. Was im Falle eines Fehlers zu geschehen hat, wird durch einen Aufruf der Funktion V_setIntErrorHandling festgelegt. Diese benötigt ein Argument des Typs V_ihand (definiert in <VecLib.h> bzw. in der Unit VecLib), das drei verschiedene Werte annehmen kann:
 
ierrNoteAusgabe einer Fehlermeldung und Fortsetzung des Programmes
ierrAbortAusgabe einer Fehlermeldung und Abbruch des Programmes
ierrIgnore Fehler ignorieren; mit dieser Option läßt sich die Fehlerbehandlung für einzelne Stellen im Programm wieder ausschalten.

Obwohl ein Aufruf von
V_setIntErrorHandling( ierrIgnore );
im Prinzip verwedet werden kann, um die Fehlerbehandlung auszuschalten, ist es stets besser, einfach die Normalversion (Präfix VI_) anstelle der VIo_-Version mit überbrückter Fehlerbehandlung zu verwenden, da die Normalversion immer um ein Vielfaches schneller ist.

nur C/C++:
Um die Überlauf-abfangede Variante nicht nur für einzelne Funktionsaufrufe, sondern überall zu verwenden, ist der einfachste Weg, die symbolische Konstante V_trapIntError im Programmkopf vor(!) Einschluß von <VecLib.h> zu definieren, z.B.
#define V_trapIntError 1
#include <VIstd.h>
#include <VImath.h>
.....
main() /* oder WinMain() oder OwlMain() */
{
  siVector SI1, SI2;
  I1 = VSI_vector( 1000 ); SI2 = VSI_vector( 1000 );
  V_setIntErrorHandling( ierrNote );
  VSI_ramp( SI1, 1000, 0, 50 ); /* hier wird ein Überlauf auftreten! */
  V_setIntErrorHandling( ierrIgnore );
  VSI_mulC( SI2, SI1, 1000, 5 );
    /* hier entsteht zwar eine ganze Serie von Überläufen, die aber alle ignoriert werden */
  ....
}

Zurück zum Inhaltsverzeichnis

5.3 Fließkomma-Fehler

Die Behandlung von Fließkomma-Fehlern lehnt sich eng an die Behandlung in den mathematischen Funktionen von C/C++ an. Überlauf-, Singularitäts- und Genauigkeits-Verlust-Fehler werden durch Setzen des in FUNKREF.HTM für die jeweilige Funktion angegebenen Standardwertes abgefangen. Bereichsfehler (DOMAIN) führen zu dem Ergebnis NAN (not-a-number).

Für jede Funktion werden die möglichen Fehlerarten, die abgefangen und behandelt werden, in der Funktions-Referenz aufgeführt. Alle von mathematischen ANSI C- oder Pascal/Delphi-Funktionen abgeleiteten VectorLib-Funktionen (also diejenigen, deren Deklaration sich in <V?math.h> bzw. den Units V?math findet) führen eine vollständige Fehlerbehandlung für jedes Vektorelement durch. Über diese Fehlerbehandlung "pro Element" hinaus wird mit Hilfe des Rückgabewertes angegeben, ob insgesamt irgendein Fehler auftrat oder nicht. Ein Rückgabewert von FALSE (0) bedeutet Fehlerfreiheit; Rückgabewerte von TRUE (ungleich 0) zeigen aufgetretene (und behandelte) Fehler an.

Nur für Debug-Bibliotheken: Wie oben bereits erwähnt, kann durch Aufruf von V_setFPErrorHandling eingestellt werden, welche Fehlerarten zu einer Meldung und welche ggf. zu einem Programm-Abbruch führen. Die vorhandenen Optionen werden durch vordefinierte Konstanten fperrXXX gesetzt:
KonstanteBedeutung
fperrIgnoreSämtliche Fließkommafehler stillschweigend behandeln
fperrNoteDOMAINBereichsfehler melden
fperrAbortDOMAINMeldung und Programmabbruch bei Bereichsfehlern
fperrNoteSINGSingularitäten (meist Divisionen durch 0) melden
fperrAbortSINGMeldung und Programmabbruch bei Singularitäten
fperrNoteOVERFLOWÜberlauf melden
fperrAbortOVERFLOW  Meldung und Programmabbruch bei Überlauf
fperrNoteTLOSSTotalen Genauigkeitsverlust (z.B. bei sin(1.e30)) melden
fperrAbortTLOSSMeldung und Programmabbruch bei Totalem Genauigkeitsverlust
fperrDefaultStandardeinstellung = fperrAbortDOMAIN + fperrNoteSING + fperrNoteOVERFLOW
 
Beim Aufruf von V_setFPErrorHandling sollten diese Konstanten addiert oder mit dem OR-Operator verknüpft werden. Man beachte, dass dies nur die Behandlung von Fehlern beeinflußt, die innerhalb von OptiVec-Funktionen auftreten. Die zu C/C++ oder Pascal/Delphi gehörenden Standard-Funktionen bleiben hiervon unberührt.

Bei der nun folgenden Beschreibung der einzelnen möglichen Fehler wird als "HUGE_VAL" der größte im jeweiligen Datentyp darstellbare Wert bezeichnet, also MAX_FLT,  MAX_DBL oder MAX_LDBL, je nach Typ. Ähnlich wird mit "TINY_VAL" der kleinste eben noch darstellbare Wert ungleich 0 bezeichnet. Dies ist nicht dasselbe wie MIN_VAL, welches der kleinste mit voller Genauigkeit darstellbare Wert ist.

Zurück zum Inhaltsverzeichnis

5.4 Die Behandlung nicht-normalisierter Zahlen

Nicht-normalisierte Zahlen (engl.: denormals) sind sehr kleine Zahlen zwischen 0 und der kleinsten in voller Genauigkeit darstellbaren Zahl des jeweiligen Datentyps. Man mag das ihnen zugrundeliegende Prinzip am folgenden vereinfachten Beispiel verstehen:
1.175494E-38 ist die kleinste normalisierte float / Single, mit 7-stelliger Genauigkeit. Was geschieht, wenn diese Zahl durch, sagen wir, 1024 geteilt wird? Das Ergebnis kann nur als 0.001145E-38 dargestellt werden, das heißt, mit nur noch 4-stelliger Genauigkeit. Die ersten drei Stellen sind ja für führende Nullen verbraucht. Auf diese Weise "vermitteln" Denormals einen sanften Übergang zwischen sehr kleinen Zahlen und 0. Generell können sie als ganz gewöhnliche Zahlen behandelt werden.

Bei der Bildung des Kehrwertes allerdings folgt ein Überlauf, und hier wird die etwas akademische Unterscheidung zwischen SING- und OVERFLOW-Fehlern fallengelassen und ein SING-Fehler angezeigt, als ob es sich um eine Division um exakt 0 handelte.

Andererseits geben Denormals als Argumente von einigen Funktionen, beispielsweise log, völlig vernünftige Ergebnisse, während exakt 0 als Argument zu einem SING-Fehler führt. Leider behandeln die meisten Compiler auch für diese Funktionen Denormals als 0. Wir schließen uns dem nicht an und berechnen lieber das Ergebnis.

Zurück zum Inhaltsverzeichnis

5.5 Fortgeschrittene Fehlerbehandlung: Meldungen in eine Datei schreiben

Allgemein bieten die mit Compilern mitgelieferten Bibliotheken dem Programmierer keine sehr gute Kontrolle über die Art, wie Fehlermeldungen ausgegeben werden. In den meisten Fällen ist dies akzeptabel. Gelegentlich möchte man aber vielleicht die Meldungen lieber in eine Datei schreiben, um nach Abarbeitung des Programms in Ruhe studieren zu können, was schiefgegangen ist. Unter Windows kommt noch hinzu, dass für jeden Fehler eine Meldungs-Box erzeugt wird, auf die der Anwender zu reagieren hat, bevor die Ausführung fortgesetzt werden kann.

Man mag dies umgehen wollen. Eine einfache Lösung dieses Problems besteht in der Funktion V_setErrorEventFile. Diese Funktion benötigt als Argumente den Namen der gewünschten Ereignis-Datei ("Log-File") und einen Schalter, ScreenAndFile, der darüber entscheidet, ob Fehlermeldungen ausschließlich in die Datei (ScreenAndFile = 0) oder außerdem noch in einer Meldungs-Box (ScreenAndFile = 1) bzw. bei Console-Programmen auch auf dem Bildschirm (ScreenAndFile = 2) auszugeben sind.

Beispiel:
V_setErrorEventFile( "MyLogFil.TXT", 0 );  /* C/C++ */
V_setErrorEventFile( 'MyLogFil.TXT', 0 );  (* Pascal/Delphi *)

Hier werden alle folgenden Fehlermeldungen nur in das Log-File MyLogFil.TXT geschrieben, aber keine auf dem Bildschirm angezeigt.
Durch Aufruf von V_setErrorEventFile( "NULL", 0 ) (C/C++) bzw. V_setErrorEventFile( 'nil', 0 ) (Pascal/Delphi) lassen sich sogar jegliche OptiVec-Meldungen vollständig unterdrücken (so sinnvoll dies auch immer sein mag).
Die Ausgabe in die Log-Datei wird beendet durch V_closeErrorEventFile. Diese letztere Funktion hat keine Argumente und gibt auch nichts zurück. Anschließend erfolgt die Ausgabe eventueller Meldungen entsprechend dem bei Erzeugung der Log-Datei angegebenen Wert von ScreenAndFile.

Man beachte, dass die beschriebene Umleitung von Fehlermeldungen nur für Fehler gilt, die innerhalb von OptiVec-Funktionen auftreten. Es steht dem Nutzer aber frei, eigene Fehlermeldungen mit der von OptiVec benutzten Funktion V_printErrorMsg auszugeben.

Einige Konfigurationen der von OptiVec unterstützten Compiler erlauben nicht den vollen Umfang der oben angegebenen Optionen. Bei manchen fehlt entweder die Ausgabe in eine Message-Box oder die Ausgabe auf den Konsolen-Bildschirm. In diesen Fällen wird ggf. eine Fehlermeldung ausgegeben und die Ausgabe auf die jeweils andere Option umgeleitet.

Zurück zum Inhaltsverzeichnis

5.6 OptiVec-Fehlermeldungen

Wie in jedem in C/C++ oder Pascal/Delphi geschriebenen Programm führen Fehler in den mathematischen Funktionen zu entsprechenden Meldungen, siehe Absatz 5.3.
Nicht nur in mathematischen Funktionen können freilich Fehler auftreten, sondern es gibt eine Reihe von Fehlern, die spezifisch für bestimmte Funktionen von OptiVec sind. Die durch sie erzeugten Meldungen werden in diesem Kapitel erläutert. Der in den Meldungen auftauchende Funktionsname ist nicht immer exakt derselbe, den Sie in Ihrem Programm geschrieben haben. So werden Sie anstelle des Präfixes VI_ gelegentlich auf VLI_ stoßen. Auch werden sich VFs_FFT oder VFp_FFT melden, wo Sie VF_FFT schrieben, wiederum abhängig vom Speichermodell. Der Grund für dieses Verhalten ist natürlich, dass viele Funktionen gemeinsamen Code benutzen und einige Namen als Synonyme für andere definiert sind.

 

(00) OptiVec/CMATH not installed correctly
(must use INSTALL.EXE !)
Nur in der Shareware-Version: Anscheinend führen Sie ein Programm, das OptiVec-Funktionen enthält, auf einem anderen Rechner aus als dem, wo Sie OptiVec installiert haben; die Weitergabe von Anwendungen, die OptiVec-Funktionen enthalten, ist aber nur mit der registrierten Vollversion möglich.
Oder OptiVec wurde durch bloßes Kopieren von Dateien installiert. Dies ist nicht möglich, da INSTALL.EXE die Uhr für die Testzeit startet. Installieren Sie OptiVec daher immer durch INSTALL.EXE.

 

(0) Trial period for OptiVec/CMATH has expired!
Nur in der Shareware-Version: Die Testzeit ist abgelaufen. Wir hoffen, Sie haben sich von den Vorzügen der Programmierung mit OptiVec überzeugen können und würden uns sehr über Ihre Registrierung freuen!

 

(1) Not enough memory.
("Nicht genug Speicherplatz")
Sie versuchen, Speicher zuzuweisen, aber es ist nicht mehr genügend vorhanden. Dieser Fehler könnte aus einem falschen Parameter size beim Aufruf von VF_vector resultieren. Ist dieser korrekt, so kämen als Grund insbesondere "vergessene Vektoren" in Schleifen in Frage, die alloziert, aber niemals freigegeben werden. Man versuche die folgenden Lösungen:
* Schnellstmögliche Freigabe aller nicht mehr gebrauchten Vektoren. Gehen Sie sicher, dass alle innerhalb eines Unterprogrammes erzeugten Vektoren wieder freigegeben werden, bevor das Unterprogramm verlassen wird.
* Lagern Sie Daten zwischendurch mittels VF_store auf Festplatte aus und lesen sie mit VF_recall wieder ein, wenn sie gebraucht werden. Diese Methode ist langsam und sollte nur im Notfall angewandt werden.

 

(2) Vector > 4 GB not possible (32-bit).
("Vektor > 4 GB nicht möglich"; nur 32-bit)
* Offenbar versuchen Sie einen Vektor zu erzeugen, dessen Größe das Maximum von 4 GB übersteigt. Wechseln Sie zu 64-bit!

 

(3) Vectors/matrices must not be identical.
("Vektoren/Matrizen dürfen nicht identisch sein")
Bei einigen Funktionen, wo mehr als ein Eingangs-Vektor (bzw. -Matrix) verwandt wird, um mehr als einen Ergebnis-Vektor zu berechnen, muss darauf geachtet werden, welcher Ergebnis-Vektor welchen Eingangs-Vektor überschreiben darf oder eben nicht. Vergleiche die Beschreibung der jeweiligen Funktion.

 

(4) Cannot use requested format (too many entries per line).
("Kann verlangtes Format nicht verwenden – zu viele Einträge pro Zeile.")
Dieser Fehler taucht bei den Ausgabe-Funktionen (VF_print usw.) auf. Der Parameter nperline wurde zu groß für den jeweiligen Datentyp und die zur Verfügung stehende Zeilenlänge angegeben. Die Funktion wählt automatisch die maximal mögliche Zahl der Einträge pro Zeile und setzt hiermit die Ausführung des Programmes fort.

 

(5) X-values of table must be distinct.
("X-Werte der Tabelle müssen unterschiedlich sein")
Die Interpolations-Routinen benötigen Tabellen, die gemäß ihren X-Werten geordnet sind. Jeder X-Wert darf nur einmal vorkommen, da unmöglich zu ein- und demselben X-Wert verschiedene Y-Werte gehören können.

 

(6) Not possible with fewer than n elements.
("Nicht möglich mit weniger als n Elementen")
Einige Funktionen verlangen das Vorhandensein einer minimalen Anzahl von n Vektor-Elementen.

 

(7) Not possible with more than n elements.
("Nicht möglich mit mehr als n Elementen")
Einige Funktionen begrenzen die Verarbeitung auf eine bestimmte Anzahl von n Vektor-Elementen (z.B. VF_polyinterpol, wo bis zu 10 Tabellen-Elemente für die Interpolation herangezogen werden können).

 

(8) Size must be an integer power of 2.
("Größe muss eine ganzzahlige Potenz von 2 sein")
Für alle Funktionen, die – explizit oder implizit – Fast-Fourier-Transform-Methoden anwenden, muss die Vektorgröße eine ganzzahlige Potenz von 2 sein. Man vergrößere oder verkleinere den/die Vektoren, um diese Bedingung zu erfüllen.

 

(9) Invalid parameter(s).
("Ungültige(r) Parameter")
In einigen Funktionen ist der zulässige Bereich eines oder mehrerer Eingabe-Parameter beschränkt. In anderen wiederum sind bestimmte Kombinationen von Eingabe-Parametern nicht erlaubt. So können Sie beispielsweise keine 9-Punkt-Interpolation mit nur 5 Datenpunkten durchführen.

 

(10) Cannot scale symbols by more than a factor of 50.
("Kann Symbole nicht mehr als fünfzigfach vergrößern." Nur Windows)
Die in den Plot-Funktionen von VectorLib verwendeten Symbole können nicht um mehr als einen Faktor 50 vergrößert werden (was allerdings bereits bedeutet, den ganzen Bildschirm mit einem einzigen Symbol zu füllen). Die Ausführung des Programmes wird nach dieser Meldung mit dem – immer noch ziemlich unsinnigen – Wert von 30 fortgesetzt.

 

(11) Cannot use line thicker than 500 pixels.
("Kann keine Linienstärke von mehr als 500 Pixels verwenden.")
Die Linienstärke in den Plot-Funktionen von VectorLib kann nicht dicker als 500 Pixels sein (was ohnehin ein ziemlich unsinniger Wert ist). Die Ausführung des Programmes wird nach dieser Meldung mit dem Wert von 500 fortgesetzt.

 

(12) Cannot free non-existent vector.
("Kann nicht-existierenden Vektor nicht freigeben.")
Sie haben V_free oder V_nfree für einen Vektor aufgerufen, dem gar kein Speicher zugeordnet ist. Die Ausführung des Programmes wird nach dieser Meldung fortgesetzt, ohne dass irgendetwas freigegeben wird. Dieser Fehler kann zwar harmlos sein (z.B., wenn Sie einen Vektor schon freigegeben haben, dies aber noch einmal versuchen). Hinter ihm könnten sich aber auch ernsthaftere Probleme verbergen, insbesondere das versehentliche Überschreiben der Vektor-Variable durch ein Speicher-Leck, z.B. beim Aufruf von Vektor- oder Matrix-Funktionen mit falschen Größen. Letzteres Problem lässt sich durch Verwendung der OptiVec-Debug-Bibliotheken detektieren und lokalisieren.

 

(21) Invalid dimension(s).
("Ungültige Dimension(en).")
Auf die eine oder andere Weise erfüllen die Dimensionen von Ein- und Ausgabematrizen nicht die in der jeweiligen Funktionsbeschreibung genannten Bedingungen.

 

(22) Matrix is singular.
("Matrix ist singulär.")
In einer Funktion, die reguläre Eingabematrizen verlangt, wurde eine singuläre Matrix angetroffen. Sie sollten eine alternative Funktion verwenden, die für die Behandlung auch (nahezu) singulärer Matrizen ausgelegt ist.

 

(23) No convergence achieved.
("Keine Konvergenz erzielt.")
Einige iterative Matrix-Methoden können in sehr seltenen Fällen scheitern, indem auch nach zahlreichen Iterations-Durchläufen keine Konvergenz erreicht wurde.

 

(24) Only the first n elements of each row can be printed.
("Kann nur die ersten n Elemente jeder Zeile ausgeben.")
Dieser Fehler taucht bei den Matrix-Ausgabefunktionen (MF_print usw.) auf, wenn die Zahl der Spalten größer ist als auf den Bildschirm paßt. Die Funktion wählt automatisch die maximal mögliche Spaltenzahl und schneidet die Zeilen am Bildschirmrand ab.

Zurück zum Inhaltsverzeichnis


6. Wenn etwas schiefgeht

Wenn Sie Probleme mit OptiVec haben, sollten Sie zuerst prüfen, ob die Installation korrekt durchgeführt wurde (s. Kap. 1.4). Weiterhin sollte man sehr genau darauf achten, die folgenden Bedingungen einzuhalten, deren Nichtbeachtung unweigerlich Schwierigkeiten nach sich zieht.

Obwohl OptiVec gründlich getestet worden ist, besteht natürlich immer die Möglichkeit, dass ein Problem unserer Aufmerksamkeit entgangen ist. Sollten Sie das Gefühl haben, auf ein solches Problem zu stoßen, so versuchen Sie doch bitte, die zu seinem Auftauchen führenden Bedingungen so genau wie möglich zu spezifizieren, und lassen Sie es uns unter support@optivec.com wissen!

Zurück zum Inhaltsverzeichnis

7. Die Include-Dateien und Units von OptiVec

Alle C/C++-Include-Dateien von OptiVec haben dieselben Namen wie die entsprechenden Pascal/Delphi-Units. Natürlich ist die Namenserweiterung unterschiedlich: ".H" für die C/C++-Include-Dateien, ".DCU" für Delphi-Units und ".TPU" oder "TPP" für Pascal-Units. Unten werden nur die Namen ohne Erweiterung aufgeführt.

Nur C/C++: Man deklariere den Gebrauch von OptiVec-Funktionen mit #include-Anweisungen. Falls Sie MFC (Microsoft Foundation Classes) oder Borlands uralte OWL (ObjectWindows Library) verwenden, müssen die MFC- oder OWL-Include-Dateien vor(!) denen von OptiVec eingeschlossen werden.

Nur Pascal/Delphi: Man deklariere den Gebrauch von OptiVec-Funktionen mit der uses-Anweisung.
 
Include-Datei (Suffix .H) oder UnitInhalt
VecLibgrundlegenden Definitionen der Datentypen und die Prototypen der allen Datentypen gemeinsamen Funktionen (das sind diejenigen mit dem Präfix V_) mit Ausnahme der Graphik-Routinen
VFstd, VDstd, VEstd"Standard-Operationen" für Fließkomma-Zahlen: Erzeugung und Initialisierung von Vektoren, Index-orientierte Manipulationen, Datentyp-Umwandlungen, I/O-Operationen, Statistik, Analysis, geometrische Vektor-Arithmetik und alle auf der Fourier-Transformation basierenden Funktionen.
VCFstd, VCDstd, VCEstd,
VPFstd, VPDstd, VPEstd
Standard-Operationen für cartesisch- und polar-komplexe Vektoren
VIstd, VBIstd, VSIstd, VLIstd, VQIstdStandard-Operationen für Ganzzahl-Vektoren mit Vorzeichen
VUstd, VUBstd, VUSstd, VULstd, VUQstd, VUIstdStandard-Operationen für vorzeichenlose Ganzzahl-Vektoren
VFmath, VDmath, VEmathAlgebraische, arithmetische und mathematische Funktionen für Fließkomma-Vektoren
VCFmath, VCDmath, VCEmath,
VPFmath, VPDmath, VPEmath
Arithmetische und mathematische Funktionen für komplexe Vektoren
VImath, VBImath, VSImath, VLImath, VQImathArithmetische und mathematische Funktionen für vorzeichenbehaftete Ganzzahl-Vektoren
VUmath, VUBmath, VUSmath, VULmath, VUQmath, VUImathArithmetische und mathematische Funktionen für vorzeichenlose Ganzzahl-Vektoren
VgraphGraphik-Funktionen für alle Datentypen
VFNLFIT, VDNLFIT, VENLFITNicht-lineare Datenanpassungs-Funktionen (nur Pascal/Delphi; in C/C++ befinden sie sich in M?std)
VFMNLFIT, VDMNLFIT, VEMNLFITNicht-lineare Datenanpassungs-Funktionen für Mehrfach-Datensätze (nur Pascal/Delphi; in C/C++ befinden sie sich in M?std)
MFstd, MDstd, MEstdMatrix-Operationen für reelle Matrizen
MCFstd, MCDstd, MCEstdMatrix-Operationen für cartesisch-komplexe Matrizen
Mgraphgraphische Darstellung von Matrizen aller Datentypen
MFNLFIT, MDNLFIT, MENLFITNicht-lineare Datenanpassungs-Funktionen für Datensätze Z = f(X, Y)  (nur Pascal/Delphi; in C/C++ befinden sie sich in M?std)
MFMNLFIT, MDMNLFIT, MEMNLFITNicht-lineare Datenanpassungs-Funktionen für Mehrfach-Datensätze Z = f(X, Y)  (nur Pascal/Delphi; in C/C++ befinden sie sich in M?std)
NEWCPLXkomplexe Klassenbibliothek CMATH; nur C++
CMATHkomplexe Bibliothek CMATH für Pascal/Delphi und C
CFMATH, CDMATH, CEMATHnur C/C++: typenspezifische Teile von CMATH
OVXMATHEinige skalare mathematische Funktionen, die intern von anderen OptiVec-Funktionen benötigt werden; sie stehen allgemein für Anwendungen zur Verfügung (siehe Kap. 9). C/C++: die Sinus-, Cosecans- und Tangens-Tabellen für VF_sinrpi2 etc. befinden sich ebenfalls hier.
FSINTAB2, DSINTAB2, ESINTAB3,
FSINTAB3, DSINTAB3, ESINTAB3
Sinus-Tabellen (nur Pascal/Delphi; für C/C++ befinden sie sich in OVXMATH)
FCSCTAB2, DCSCTAB2, ECSCTAB3,
FCSCTAB3, DCSCTAB3, ECSCTAB3
Cosecans-Tabellen (nur Pascal/Delphi; für C/C++ befinden sie sich in OVXMATH)
FTANTAB2, DTANTAB2, ETANTAB3,
FTANTAB3, DTANTAB3, ETANTAB3
Tangens-Tabellen (nur Pascal/Delphi; für C/C++ befinden sie sich in OVXMATH)
VecObjgrundlegende Definitionen für VecObj, das Objekt-orientierte Interface für C++
fVecObj, dVecObj, eVecObjMember-Funktionen von VecObj für reelle Vektor-Objekte (nur C++)
cfVecObj, cdVecObj, ceVecObj
pfVecObj, pdVecObj, peVecObj
Member-Funktionen von VecObj für komplexe Vektor-Objekte (nur C++)
iVecObj, biVecObj, siVecObj, liVecObj, qiVecObjMember-Funktionen von VecObj für vorzeichenbehaftete Ganzzahl-Vektor-Objekte (nur C++)
uVecObj, ubVecObj, usVecObj, ulVecObj, uiVecObjMember-Funktionen von VecObj für vorzeichenlose Ganzzahl-Vektor-Objekte (nur C++)
OptiVecschließt das gesamte OptiVec-Paket ein (nur C++)
VecAllschließt alle VectorLib- und CMATH-Funktionen ein (nur C oder C++)
MatAllschließt alle MatrixLib-Funktionen ein (nur C oder C++)
 

Zurück zum Inhaltsverzeichnis


E N D E

Copyright für OptiVec Software und Dokumentation
© 1996-2024 OptiCode –Dr. Martin Sander Software-Entwicklung
Alle Rechte vorbehalten.