vb@rchiv
VB Classic
VB.NET
ADO.NET
VBA
C#
SEPA-Dateien erstellen inkl. IBAN-, BLZ-/Kontonummernprüfung  
 vb@rchiv Quick-Search: Suche startenErweiterte Suche starten   Impressum  | Datenschutz  | vb@rchiv CD Vol.6  | Shop Copyright ©2000-2024
 
zurück
Rubrik: .NET   |   VB-Versionen: VB.NET01.06.06
Keine Überwachung der Gleitkomma-Arithmetik in VB.NET

VB.NET löst bei einem Überlauf der Gleitkomma-Arithmetik in DOUBLE-Variablen keinen Fehler aus, das betroffene Programm stürzt aber auch nicht ab. Bei der Umstellung von VB6-Programmen auf VB.NET ist zu beachten, dass die ON ERROR GOTO-Fehlerbehandlung beim Gleitkomma-Überlauf nicht mehr die gewohnten auffangbaren Fehler auslöst.

Autor:  Manfred BohnBewertung:     [ Jetzt bewerten ]Views:  14.507 

VB.NET löst bei einem Überlauf der Gleitkomma-Arithmetik in DOUBLE-Variablen keinen Fehler aus, das betroffene Programm stürzt aber auch nicht ab. Bei der Umstellung von VB6-Programmen auf VB.NET ist zu beachten, dass die ON ERROR GOTO-Fehlerbehandlung beim Gleitkomma-Überlauf nicht mehr die gewohnten auffangbaren Fehler auslöst.

Einführung

VB.NET löst bei einem Überlauf der Gleitkomma-Arithmetik in DOUBLE-Variablen keinen Fehler aus, das betroffene Programm stürzt aber auch nicht ab.

Bei der Umstellung von VB6-Programmen auf VB.NET ist zu beachten, dass die ON ERROR GOTO-Fehlerbehandlung beim Gleitkomma-Überlauf nicht mehr die gewohnten auffangbaren Fehler auslöst.

Es stellt sich die Frage: Was geschieht eigentlich in einem Programm, das nach einem Gleitkomma-Fehler einfach weiterläuft?
Was wird da eigentlich gerechnet?
Oder genauer: Womit muss man als Programmierer bzw. als Anwender in solch einem Fall rechnen?

Die im Folgenden mitgeteilten (unvollständigen!) Befunde sind durch Herumprobieren mit VB.NET 2005 EE ermittelt worden.

Der Datentyp DOUBLE enthält für Reaktionen auf den Überlauf der Gleitkomma-Arithmetik drei Sonderwerte:

  • NAN = "not an arithmetic expression" / "not a number" = -1.#IND
  • PositiveInfinity = "+unendlich" = 1.#INF
  • NegativeInfinity = "-unendlich" = -1#.INF

Den Begriff INFINITY verwende ich - wie in VB.NET üblich - als übergeordnete Bezeichnung für Positive- und Negative-Infinity-Werte. Genau genommen gibt es noch weitere "specials", die in VB.NET manchmal auftreten (z.B. QNAN statt NAN), auf die ich aber nicht näher eingehen will. Diese ganzen Sonderwerte korrespondieren mit Konventionen des IEEE-Formats.

Dieser Workshop ist nicht als ein Regelwerk für den Umgang mit DOUBLE-Sonderbedingungen zu verstehen, sondern als eine Warnung für Umsteiger, die Programmiersprachen gewohnt sind, die solche Zustände und die daraus resultierenden Operationen nicht kennen.

1. Die Sonderwerte "PositiveInfinity" und "NegativeInfinity"
Zu der Konstanten "PositiveInfinity" informiert die VB-Dokumentation wie folgt:

Der Wert dieser Konstanten ist das Ergebnis einer Division einer positiven Zahl durch null. Diese Konstante wird zurückgegeben, wenn das Ergebnis einer Operation größer als die Konstante "Double.MaxValue" ist. Verwenden Sie "IsPositiveInfinity" um festzustellen, ob ein Wert "+unendlich" ist. Durch einen Vergleich mit einem PositiveInfinity-Wert ist nicht feststellbar, ob ein Wert "+unendlich" ist.

Klingt mysteriös! Versuchen wir, es aufzuklären ...

Es werden hier zwei Fehlerbedingungen miteinander vermischt: Der DivisionByZero-Error und der Overflow-Error. (Nicht jeder wird die Verwendung des Begriffs "Fehler" oder "Ausnahme" in diesem Zusammenhang akzeptieren, sondern stattdessen vielleicht eher "Sonderzustand" favorisieren. Es ist aber gute VB-Tradition, das so zu bezeichnen.)

Beide Fehlerbedingungen in der Gleitkomma-Arithmetik liefern zwar den "gleichen" Wert "+unendlich", aber VB-intern werden sie offenbar unterschieden.

Dim x, y As Double
 
x = 1.0E+308 : y = 1.0E+308
 
If Double.IsPositiveInfinity(x + y) Then Stop
If Double.IsPositiveInfinity(5.0 / 0.0) Then Stop

Beide Stopp-Bedingungen werden ausgelöst. (x+y) erzeugt den Überlauf-Infinity, weil das Ergebnis die Konstante Double.MaxValue überschreitet; (5.0 / 0.0) erzeugt den DivisionByZero-Infinity.

Dass diese beiden Infinity-Varianten tatsächlich unterschieden werden, zeigt sich an folgenden Beispielen (x, y wie oben):

If 5.0 / 0.0 = 6.0 / 0.0 Then Stop
If (x + y) = (x * 2) Then Stop
 
If (5.0 / 0.0) = (x + y) Then Stop

Die ersten beiden Stopp-Bedingungen werden ausgelöst, weil hier jeweils die gleichen Fehlerarten verglichen werden. Die dritte Stopp-Bedingung wird nicht ausgelöst, obwohl auch hier beide Terme eigentlich "PositiveInfinity" liefern - aber ihnen eben zwei unterschiedliche Fehler-Typen zugrunde liegen.

If 5.0 / 0.0 = Double.PositiveInfinity Then Stop
If CDbl(x + y) = Double.PositiveInfinity Then Stop
 
If x + y = Double.PositiveInfinity Then Stop

Die ersten beiden Stopp-Bedingungen werden ausgelöst, die dritte nicht. Der Overflow-Error ist erst nach expliziter Umwandlung in einen Double-Wert tatsächlich durch den Gleichheitsoperator als "PositiveInfinity" zu identifizieren.

Wie verhält sich INFINITY nach der Zuweisung auf eine Double-Variable?

Dim x, y, dbz, ofl As Double
 
x = 1.0E+308 : y = 1.0E+308
dbz = 5.0 / 0.0 : ofl = x + y
 
If dbz = ofl Then Stop
If dbz = Double.PositiveInfinity Then Stop
If ofl = Double.PositiveInfinity Then Stop

Alle drei Stopp-Bedingungen werden ausgelöst.

Das Gleiche gilt entsprechend für den Sonderwert "NegativeInfinity".

Falls ein Ausdruck einen Fehler in der Gleitkomma-Arithmetik auslöst, enthält die Ergebnis-Variable vom Typ Double den Wert "PositiveInfinity" bzw. "NegativeInfinity", unabhängig von der Art des Fehlers.

Es gibt allerdings eine wichtige Ausnahme: 0.0 / 0.0 --> Sonderwert: NAN

Die VB-Dokumentation (2005) hält übrigens (5.0 / 0.0) = "PositiveInfinity" für mathematisch völlig korrekt: "In the previous procedure, 'Infinity' might not be what you expected, but it is mathematically correct - 0 goes into 5 an infinite number of times."

In meinem Handbuch der Mathematik steht ROT UNTERLEGT für reelle Zahlen:
"Durch Null kann nicht dividiert werden."
Durch die geschickte Formulierung "goes into" wird dies in der VB-Dokumentation elegant umgangen.

Eigentlich ist die Bezeichnung "mathematisch korrekt" hier überhaupt nicht anwendbar. Der Datentyp DOUBLE bildet (weitgehend) die IEEE-Konventionen ab und dient nicht der möglichst präzisen Umsetzung der reellen Zahlen in ein digitales System. Er unterliegt deshalb auch nicht der Beurteilung aus der Perspektive einer mathematischen Axiomatik.

2. Was geschieht bei der Ausführung der mathematischen Methoden?
Hier muss man unterscheiden, ob das Funktionsargument den mathematischen bzw. numerischen Voraussetzungen der Funktion widerspricht (Fehlertyp: ungültiges Argument), oder ob es sich um einen Überlauf-Fehler handelt.

Beispiele:

Dim erg As Double
 
erg = Math.Log(-1)                     ' ungültiges Argument (->NAN)
erg = Math.Sqrt(-1)                    ' ungültiges Argument (->NAN) 
erg = Math.Exp(900)                    ' Überlauf des Datentyps (->INFINITY)
erg = Math.Tan(2.0# * Math.Atan(1.0#)) ' nun ja

Allgemein: Bei einem ungültigen Argument wird die Ergebnisvariable auf den Wert NAN gesetzt, bei einem Überlauf wird das Ergebnis positiv oder negativ INFINITY.
Interessant: Der Tangens von 90 Grad wird wegen der mangelnden Rechengenauigkeit der Funktion nicht auf "+unendlich" gesetzt, sondern liefert einen hohen Double-Wert.

Das Verhalten der mathematischen Methoden, wenn INFINITY-Werte als Funktions-Argumente auftreten, besitzt eine gewisse innere Schlüssigkeit:Es gilt: die Wurzel eines Wertes kleiner 0.0 ist undefiniert, die Wurzel eines unendlich großen Wertes ist unendlich.

Dim erg, dbz As Double
 
dbz = (5.0 / 0.0)
erg = Math.Sqrt(dbz)
If Double.IsPositiveInfinity(erg) Then Stop
 
dbz = (-5.0 / 0.0)
erg = Math.Sqrt(dbz)
If Double.IsNaN(erg) Then Stop

Beide Stopp-Bedingungen werden ausgelöst.

Falls ein INFINITY-Argument bei mathematischen Funktionen auftritt, kann es zum "Umschlagen" in einen gültigen Wert kommen: exp(-unendlich) = 0.0. Dieses Funktionsergebnis ist - für sich betrachtet - durchaus begründbar. Innerhalb umfangreicher Terme auftretend, verschleiert es aber eventuell wirkungsvoll den Umstand, dass ein Gleitkomma-Überlauf aufgetreten ist. Zur ATAN-Methode berichtet die VB-Dokumentation, dass der Wert (-PI / 2) bzw. (+PI / 2) zurückgegeben wird, wenn ein INFINITY-Argument übergeben worden ist.

Weitere Beispiele:

log(+unendlich) = +unendlich (Details zum Verhalten von Math.Log: vgl. unbedingt VB-Dokumentation)
abs(-unendlich) = +unendlich
sign(-unendlich) = -1.0

Zum Verhalten der POW-Funktion in Bezug auf die Sonderwerte gibt die VB-Dokumentation detailliert Auskunft. Es werden 16 (!) Fälle unterschieden; in neun dieser Fälle wird in der Ergebnis-Variable einer der Sonderwerte eingetragen.

Es empfiehlt sich aus den genannten Gründen, die jeweils benötigten mathematischen VB-Funktionen in eigenen Routinen zu kapseln und vor der Ausführung auf Gültigkeit bzw. Ausprägung des Arguments abzufragen - dabei ggf. den Fehler "ungültiges Argument" (Fehlernummer 5) bzw. "Überlauf" (Fehlernummer 6) per Code auszulösen. Sehr viel weniger effizient ist es, wenn zuerst die Funktion ausgeführt, das Ergebnis auf die Double-Variable "erg" zugewiesen, und folgende Kontroll-Abfrage angehängt wird:

If Double.IsInfinity(erg) Or Double.IsNaN(erg) Then Err.Raise(5)

Durch diese Abfrage kann der Rechenzeitbedarf einer Funktion um ca. 30-100 % anwachsen. Insbesondere bei Funktionen, die sehr häufig aufgerufen werden, ist das beachtlich.

3. Wie wird mit diesen Sonderwerten in arithmetischen Rechenoperationen verfahren?
Grundsätzlich kann fast jede arithmetische Operation im Ergebnis zu einem DOUBLE-Überlauf führen. Wenn dieser "Variablen-Zustand" im Programm nicht abgefangen oder abgefragt wird, tritt unweigerlich die Situation ein, dass mit den Sonderwerten auch "gerechnet" wird. Was auch immer das dann für Folgen haben mag!!

Im Einzelnen:

Für Infinity-Werte gelten dabei die allgemeinen Rechenregeln für Vorzeichen:

+unendlich * -unendlich = -unendlich -unendlich * -unendlich = +unendlich

Dieses Vorzeichenverhalten gilt auch für die Multiplikation eines gültigen Double-Wertes mit einem Infinity-Wert.
Allerdings: Multiplikation eines INFINITY-Wertes mit 0.0 führt im Ergebnis zum Sonderwert NAN.
Division eines INFINITY-Wertes durch 0.0 führt im Ergebnis wieder zu INFINITY.

Addition oder Subtraktion einer beliebigen Menge gültiger Werte zu/von INFINITY-Werten ändert die unendlich-Werte nicht. Das gilt auch für Addition bzw. Subtraktion des Wertes 0.0. Bedingte Schleifen (z.B. DO ... WHILE), bei denen auf Differenzen abgefragt wird, sprechen deshalb eventuell nicht mehr an und werden zu Endlos-Schleifen.

Eine Variable, die auf  "+unendlich" gesetzt worden ist, wird bei Vergleichsabfragen - wie zu erwarten - größer als die Konstante "Double.MaxValue" erkannt. Der Wert "-unendlich" ist dementsprechend kleiner als "Double.MinValue". Falls in einem Programmabschnitt vorausgesetzt wird, dass die Werte der verarbeiteten DOUBLE-Variablen innerhalb der gültigen Grenzen liegen, kann das zu unerwarteten Operationen führen.

Das Aufeinandertreffen von zwei INFINITY-Werten führt MANCHMAL zum Entstehen eines NAN-Wertes:

+unendlich - +unendlich = NAN (jedoch: +unendlich + +unendlich = +unendlich !!)
+unendlich / +unendlich = NAN (jedoch: +unendlich * +unendlich = +unendlich !!)

Man darf bei den Infinity-Werten nicht mit einem Verhalten rechnen, das dem gültiger Werte entspricht. Stattdessen gilt für sie eine spezifische Operations-Logik.

Ein Infinity-Wert, der innerhalb einer Berechnung auftritt, kann im Ergebnis durchaus zu einem gültigen Double-Wert führen:

GültigerWert / +unendlich = 0.0
GültigerWert / -unendlich = 0.0

Das erscheint - nach der Einführung von INFINITY - zunächst logisch als durchaus folgerichtig. Die unendliche Aufteilung eines Wertes führt zu Null. Diese Eigenart ist aber besonders "gefährlich". Wenn in einer komplexen Gleichung unerkannt ein Infinity-Wert auftritt, der sofort im Rahmen einer Division "genullt" wird, kann das Gesamtresultat einen gültigen (aber häufig sinnlosen) Wert ergeben.

Bei Beteiligung an Ganzzahl- oder Modulo-Divisionen lösen INFINITY-Werte einen Überlauf-Fehler aus, weil die implizite Typumwandlung in eine Ganzzahl scheitert. Das gilt auch für das Verhalten expliziter Typumwandlungsroutinen für Ganzzahlen (z.B. CINT). Die Überwachung der Ganzzahl-Arithmetik reagiert auf die IEEE-Sonderwerte mit dem Auslösen der entsprechenden "Ausnahme". Das Phänomen besteht darin, dass INFINITY-Werte nicht einfach "undefinierte" Werte sind, sondern eine eigenständige numerische Logik besitzen. Dem muss man entweder sorgsam aus dem Weg gehen - also alle irgendwo möglichen Gleitkomma-Überläufe und unzulässigen Funktionsaufrufe abfangen - oder: man muss lernen, mit diesen Sonderwerten sinnvoll umzugehen. Hierfür muss man deren Verhalten ganz genau kennen ....

4. Der Sonderwert NAN
Der NAN-Sonderwert zeigt - im Vergleich zu INFINITY - ein simples Verhalten. Bei ihm ist klar, dass es sich definitionsgemäß um keinen numerischen Wert handelt und jede numerische Operation, in der er dennoch auftritt, wieder einen NAN-Wert liefern muss. (Zumindest konnte ich beim Herumprobieren keine Ausnahme finden!)

Die mathematischen Funktionen akzeptieren den Sonderwert NAN als Argument und liefern dann NAN auch im Ergebnis zurück. Bei Anwendung mathematischer Funktionen auf INFINITY-Werte entstehen ebenfalls manchmal NAN-Werte, z. B. bei den Winkelfunktionen SIN, COS, TAN (vgl. aber ATAN). Die Sign-Funktion löst bei einem NAN-Wert als Argument einen auffangbaren Laufzeitfehler aus:

sign(NAN) ---> Fehler

Der Sonderwert NAN kann nicht durch direkten Vergleich mit der entsprechenden VB-Konstante abgefragt werden, stattdessen muss zwingend die Funktion Double. IsNAN verwendet werden. (obwohl beide Werte in der IDE identisch als -1#IND angezeigt werden - also Vorsicht !!)

Dim nan As Double
 
nan = 0.0 / 0.0
 
If nan = Double.NaN Then Stop
If Double.IsNaN(nan) Then Stop

Nur die zweite Stopp-Bedingung wird ausgelöst !!

Ist das unerkannte Auftreten von NAN-Werten in einer Funktion deshalb relativ harmlos, weil Funktions-Rückgaben nahezu zwangsläufig ebenfalls NAN-Werte annehmen? Leider nicht.

Umgewandelt in eine boolsche Variable (z.B. VB-Funktion: "CBOOL") liefert eine Double-Variable, die auf NAN gesetzt worden ist, stets den Wert "TRUE". Beim Vergleich von NAN mit einem gültigen numerischen Wert oder mit einem zweiten NAN-Wert ergibt sich immer "FALSE". Unerkannte NAN-Werte können deshalb die Abfragelogik in einer Routine aushebeln.

Dim z As Double
 
z = Math.Log(-1) '--> NAN
 
If CBool(z) Then Stop
 
If z > 100 Then Stop
If z = 100 Then Stop
If z < 100 Then Stop

Nur die erste STOPP-Bedingung wird ausgelöst.

Alle drei Vergleiche mit dem gültigen Wert 100 werden als "FALSE" weiterverarbeitet.

Der Vergleich einer nicht-numerischen Kennung mit einem gültigen numerischen Wert müsste eigentlich zwingend eine "Ausnahme" auslösen. Der Vergleich einer STRING-Variable, die einen nicht-numerischen Inhalt hat, mit einem zulässigen Double-Wert wird nicht durchgeführt, sondern führt zu einem Fehler ("Conversion is not valid"). Das Verhalten von NAN ist in dieser Hinsicht also absolut ungewöhnlich. Im Code führt diese Eigentümlichkeit zu Problemen wie dem Folgenden:

If z > 100 Then
  ' erwartet: z > 100
  'inclusive: z = PositiveInfinity
ElseIf z < 100 Then
  ' erwartet: z < 100
  'inclusive: z = NegativeInfinity
Else
  ' erwartet: z = 100
  ' inclusive: z = NAN
End If

Folgender Code ist stattdessen erforderlich, um den Sonderwert NAN zu identifizieren:

If z > 100 Then
  ' erwartet: z > 100
  ' inclusive: z = PositiveInfinity
ElseIf z < 100 Then
  ' erwartet: z < 100
  ' inclusive: z = NegativeInfinity
ElseIf z = 100 then 
  ' erwartet: z = 100
Else
  ' z = NAN
End If

Aus Performancegründen sollte auf eine Abfrage durch die Methode Double.IsNan möglichst verzichtet werden.

5. Was sonst noch wichtig sein könnte ....
Ein Infinity-Wert, der bei einer Variable des Datentyps SINGLE auftritt, wird bei Zuweisung auf eine DOUBLE-Variable zum Double-Infinity und umgekehrt.

Ein Infinity-Wert in einer Variable des Typs SINGLE entspricht - bei wertebezogenen Operationen und Vergleichen - dem Infinity-Wert in einer Double-Variable (sng = dbl).

Auf Grund impliziter Typumwandlung können Operationen / Funktionen, deren Eingabevariable nicht vom Typ DOUBLE sind, im Ergebnis DOUBLE-Werte liefern, die dann auch ggf. die beschriebenen Sonderwerte enthalten.

Ein Beispiel:

Dim i, k As Short
 
i = 100 : k = 0
 
If i / k > 40000 Then Stop

Auf den ersten Blick erwartet man nicht, dass diese STOPP-Bedingung jemals ausgelöst werden könnte. Der Datentyp SHORT erlaubt bekanntlich keine Werte in der Größe 40000. Zudem vermutet man wahrscheinlich, dass die Division von ganzzahligen Werten mit einem Divisor 0 zu einem Ganzzahl-Arithmetik-Alarm führt. Die Division liefert aber im Ergebnis den Datentyp DOUBLE, löst keinen Alarm aus und weil die Variable k auf 0 steht, erhält dieser DOUBLE-Ergebniswert den Sonderwert "PositiveInfinity" zugewiesen. Und INFINITY ist nun mal größer als 40000 definiert. Die obige STOPP-Bedingung wird deshalb ausgelöst.

If CINT(i / k) > 40000 Then Stop

In diesem Fall kommt es zum Overflow-Error, weil der entstehende INFINITY-Wert nicht durch die Funktion "CINT" umgewandelt werden kann.

Dim i, k As Short
 
i = 0 : k = 0
 
If i / k > 40000 Then Stop
If i / k <= 40000 Then Stop

Diese beiden Stopp-Bedingungen werden nicht ausgelöst, weil im Ergebnis-DOUBLE der Sonderwert NAN auftritt und dieser Wert liefert beim Vergleich mit gültigen Werten immer FALSE.

6. Wie kann man sein VB-Programm vor den Kapriolen der IEEE-Sonderwerte schützen?
Man kann umfangreiche numerische Algorithmen zunächst in VB6 implementieren und testen. VB6 löst immer auffangbare Laufzeitfehler aus und rechnet deshalb nie mit den IEEE-Sonderwerten. Sobald man alle Bedingungen, die zu einem Gleitkomma-Überlauf führen könnten, unter Kontrolle gebracht hat, kann man den Code in VB.NET "transportieren". Die Übertragung in VB.NET ist in solchen Fällen relativ unaufwendig und kann weitgehend vom Umstellungsassistenten gemeistert werden. Eine EFFIZIENTE Lösung des Problems innerhalb von VB.NET ist mir leider nicht bekannt. Man kann versuchen, komplizierte Routinen auf eine Anzahl von überschaubaren Funktionen zu reduzieren, bei denen dann Code-technisch ausgeschlossen werden kann, dass es jemals zu Gleitkomma-Überläufen kommt. Das geht oft überhaupt nicht oder es ist mit erheblichem Aufwand verbunden. Man kann Gleitkomma-Operationen statt mit DOUBLE-Werten auch mit dem Datentyp DECIMAL ausführen. Intern realisiert dieser Datentyp nicht das IEEE-Format und liefert deshalb auch keine Sonderwerte. Im Grunde ist es ein Ganzzahltyp mit angelagerter Dezimalpunkt-Arithmetik. Da ich mich zu diesem Datentyp im Rahmen von VB6 bereits ausführlich geäußert habe, hier nur kurz eine Liste der zu beachtenden Eigenarten:

  • im Vergleich zu DOUBLE stark eingeschränkter Wertebereich
  • höherer Speicher- und Rechenzeitbedarf
  • sehr hohe Rechengenauigkeit
  • spezifisches Verhalten von VB-Funktionen bezüglich dieses Datentyps (Nur die konsequente Anwendung der VB-Umwandlungsfunktion CDEC sichert Berechnungen, die mit DECIMAL-Werten durchgeführt werden.)

Die Mehrzahl der veröffentlichten numerischen Verfahren bezieht sich auf DOUBLE-(ähnliche) Variable und ist entsprechend abgestimmt und optimiert. Insbesondere die hohe Rechengenauigkeit von DECIMAL kann im Einzelfall bei der Übertragung Probleme verursachen:

  • iterative Algorithmen zeigen ein anderes Konvergenz-Verhalten (Schrittweiten und max. zulässige Schrittzahlen sind anzupassen)
  • Verfahren zur Bestimmung von Startwerten liefern evtl. zu ungenaue Eingangswerte und müssen deshalb ausgetauscht werden
  • die Ausprägung von Epsilon-Schranken und von tolerierten Fehler-Abweichungen muss ggf. modifiziert werden
  • Eingabewerte sind geeignet zu skalieren, um Variablen-Überläufe zu verhindern
  • zusätzliche Zwischenergebnis-Rundungen können erforderlich werden

Die Verwendung des Datentyps DECIMAL ist deshalb nur bedingt empfehlenswert.

Man kann - um sicherzugehen - den unvorteilhaften Weg einschlagen und statt DOUBLE-Variablen Instanzen einer Klasse verwenden, die eine Variable des Datentyps DOUBLE kapselt und alle Wert-Zuweisungen auf diese Variable überwacht. Diese Strategie führt allerdings zu einem erheblichen Anwachsen des Rechenzeitbedarfs bei Ausführung umfangreicher Gleitkomma-Operationen. Zudem sind Anpassungen des rufenden Quellcodes erforderlich. Der Anpassungs-Aufwand lässt sich ab VB.NET 2005 durch die Überladung von arithmetischen und logischen Operatoren erheblich vermindern.

Vielleicht (Ich behaupte: mit an Sicherheit grenzender Wahrscheinlichkeit) werden kommende Versionen von VB.NET die Überwachung der Gleitkomma-Operationen wieder beinhalten. Man kann also auch abwarten und Tee trinken .....

7. Überwachung der Gleitkomma-Arithmetik durch die Klasse "cDouble"
Die Beispiel-Klasse "cDouble" kapselt einen einfachen Double-Wert und überwacht alle Zuweisungen auf diese Variable (Private Property DoubleK). Das Auftreten von INFINITY-Werten löst den Fehler "Überlauf" aus, das Auftreten von NAN-Werten den Fehler "ungeeignetes Argument". Diese Fehler können vom rufenden Programm in Try-Catch-Blöcken oder durch "ON ERROR GOTO" verarbeitet werden. Zuweisung/Abfrage von DOUBLE-Werten auf Instanzen der Klasse erfolgt durch deren öffentliche Eigenschaft "DoubleX". Zuweisung von Werten aus anderen Instanzen dieser Klasse erfolgt durch die öffentliche Eigenschaft "Value". Die Klasse überlädt eine Reihe von mathematischen und logischen Operatoren, sowie einige mathematische Funktionen (LOG, SQRT, POW). (Warnung: Der Code der Klasse ist zwar halbwegs, aber nicht umfassend getestet.)

Sollen in einer Routine statt DOUBLE-Variablen Instanzen dieser Klasse verwendet werden, sind im wesentlichen folgende Anpassungen des Codes der Routine erforderlich: (Eine Klasse, die weniger Anpassung im Code erfordert, ist mir leider nicht eingefallen. Meine Kenntnisse in VB.NET sind aber ziemlich bescheiden. Insbesondere kann man in VB.NET offenbar keine parameterfreie DEFAULT PROPERTY programmieren.)

Dim X, Y, Z as Double --> Dim X, Y, Z as New cDouble
 
X = 502.123 --> X.DoubleX = 502.123
X = Y --> X.Value = Y (Warnung: X=Y setzt eine Referenz !!)
 
Z = (X+Y) --> Z = (X+Y)
X = Sqrt(Z) --> X = Z.Sqrt oder X = Sqrt(Z.DoubleX)
Z = X ^ Y --> Z = X.Pow(Y)
Z = 1 / X --> Dim eins as new cdouble: eins.DoubleX = 1.0 : Z = eins / X
Z = Abs((X-Y)/(X+Y)) --> Z = ((X-Y)/(X+Y)).Abs oder Z = Abs(((X-Y)/(X+Y)).DoubleX)
Z = Exp(x) --> Z = Exp(X.DoubleX)
 
If Z + X > Y Then … --> If Z + X > Y ThenIf Abs(X-Y) < eps Then …. --> If X = Y Then

Dieser Workshop wurde bereits 14.507 mal aufgerufen.

Über diesen Workshop im Forum diskutieren
Haben Sie Fragen oder Anregungen zu diesem Workshop, können Sie gerne mit anderen darüber in unserem Forum diskutieren.

Neue Diskussion eröffnen

nach obenzurück


Anzeige

Kauftipp Unser Dauerbrenner!Diesen und auch alle anderen Workshops finden Sie auch auf unserer aktuellen vb@rchiv  Vol.6
(einschl. Beispielprojekt!)

Ein absolutes Muss - Geballtes Wissen aus mehr als 8 Jahren vb@rchiv!
- nahezu alle Tipps & Tricks und Workshops mit Beispielprojekten
- Symbol-Galerie mit mehr als 3.200 Icons im modernen Look
Weitere Infos - 4 Entwickler-Vollversionen (u.a. sevFTP für .NET), Online-Update-Funktion u.v.m.
 
   

Druckansicht Druckansicht Copyright ©2000-2024 vb@rchiv Dieter Otter
Alle Rechte vorbehalten.
Microsoft, Windows und Visual Basic sind entweder eingetragene Marken oder Marken der Microsoft Corporation in den USA und/oder anderen Ländern. Weitere auf dieser Homepage aufgeführten Produkt- und Firmennamen können geschützte Marken ihrer jeweiligen Inhaber sein.

Diese Seiten wurden optimiert für eine Bildschirmauflösung von mind. 1280x1024 Pixel