Dieser Abschnitt behandelt folgende Themen:
Ein Feld (Datenbankfeld oder Benutzervariable), das in einer arithmetischen Operation als Operand verwendet werden soll, muss mit einem der folgenden Formate definiert werden:
| Format | |
|---|---|
| N | Numerisch ungepackt |
| P | Numerisch gepackt |
| I | Integer (Ganzzahl) |
| F | Floating Point (Gleitkomma) |
| D | Datum |
| T | Zeit |
Anmerkung
Reporting Mode: Ein Feld, das in einer arithmetischen Operation als Operand verwendet
werden soll, muss vorher definiert werden. Benutzervariablen oder Datenbankfelder, die in
einer arithmetischen Operation als Ergebnisfeld verwendet werden, müssen nicht vorher
definiert werden.
Sobald ein Programm zur Ausführung aufgerufen wird, werden alle im DEFINE DATA-Bereich definierten
Benutzervariablen und Datenbankfelder mit den entsprechenden Leer- bzw. Nullwerten
initialisiert.
Die Datenübertragung erfolgt mit einem MOVE- oder COMPUTE-Statement. Die folgende Tabelle fasst die
Kompatibilitätsregeln zur Datenübertragung der Formate zusammen, die ein Operand
annehmen kann.
| Ausgangsfeld | Zielfeld | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| N oder P | A | U | Bn (n<5) | Bn (n>4) | I | L | C | D | T | F | G | O | |
| N oder P | Y | [ 2 ] | [ 14 ] | [ 3 ] | - | Y | - | - | - | Y | Y | - | - |
| A | - | Y | [ 13 ] | [ 1 ] | [ 1 ] | - | - | - | - | - | - | - | - |
| U | - | [ 11 ] | Y | [ 12 ] | [ 12 ] | - | - | - | - | - | - | - | - |
| Bn (n<5) | [ 4 ] | [ 2 ] | [ 14 ] | [ 5 ] | [ 5 ] | Y | - | - | - | Y | Y | - | - |
| Bn (n>4) | - | [ 6 ] | [ 15 ] | [ 5 ] | [ 5 ] | - | - | - | - | - | - | - | - |
| I | Y | [ 2 ] | [ 14 ] | [ 3 ] | - | Y | - | - | - | Y | Y | - | - |
| L | - | [ 9 ] | [ 16 ] | - | - | - | Y | - | - | - | - | - | - |
| C | - | - | - | - | - | - | - | Y | - | - | - | - | - |
| D | Y | [ 9 ] | [ 16 ] | Y | - | Y | - | - | Y | [7] | Y | - | - |
| T | Y | [ 9 ] | [ 16 ] | Y | - | Y | - | - | [ 8 ] | Y | Y | - | - |
| F | Y | [ 9 ] [ 10 ] | [ 10 ] [ 16 ] | [ 3 ] | - | Y | - | - | - | Y | Y | - | - |
| G | - | - | - | - | - | - | - | - | - | - | - | Y | - |
| O | - | - | - | - | - | - | - | - | - | - | - | - | Y |
Legende:
| Y | Übertragung möglich. |
|---|---|
| - | Übertragung nicht möglich. |
| [ ] | Übertragung möglich. Die Ziffern in eckigen Klammern [ ] beziehen sich auf die entsprechende Regel für die Übertragung (siehe unten). |
Bei der Umsetzung von Werten in ein anderes Format gelten folgende Regeln:
Von Alphanumerisch (A) in Binär (B):
Der Wert wird Byte für Byte von links nach rechts übertragen. Je nach Länge des
Zielfeldes und der Anzahl der Bytes wird der Wert entweder abgeschnitten oder der
Rest des Feldes mit Leerzeichen aufgefüllt.
Von Numerisch (N), Gepackt (P), Ganzzahl (I) und Binär (B) mit 1-4 Bytes Länge
in Alphanumerisch:
Der Wert wird in ungepacktes Format umgesetzt und linksbündig in das Zielfeld
übertragen, wobei vorangestellte Nullen weggelassen werden und der Rest des Feldes
mit Leerzeichen aufgefüllt wird. Bei negativen numerischen Werten wird das
Vorzeichen in die Hexadezimalnotation Dx
umgesetzt. Ein Komma (Dezimalpunkt) im Ausgangswert wird nicht berücksichtigt, und
alle Stellen vor und nach dem Komma werden als ganze Zahl interpretiert.
Von Numerisch (N), Gepackt (P), Ganzzahl (I), Gleitkomma (F) in Binär (B) mit
1-4 Bytes Länge:
Der Wert wird in binäres Format umgesetzt (4 Bytes). Ein Komma (Dezimalpunkt) wird
ignoriert, die Stellen vor und nach dem Komma werden als ganze Zahl behandelt. Je
nach Vorzeichen ist die Binärzahl entweder positiv oder das Zweierkomplement des
Wertes.
Von Binär (B) mit 1-4 Bytes Länge in Numerisch (N):
Der Wert wird umgesetzt und rechtsbündig übertragen, der Rest des Feldes wird mit
Nullen aufgefüllt. Binäre Werte von 1 bis 3 Bytes Länge werden immer als positiv
interpretiert. Bei 4 Byte langen binären Werten bestimmt das erste (linke) Bit das
Vorzeichen: 1 = negativ, 0 = positiv. Ein Komma (Dezimalpunkt) im Zielfeld wird
nicht berücksichtigt, und alle Stellen vor und nach dem Komma werden als ganze Zahl
interpretiert.
Von Binär (B) in Binär (B):
Der Wert wird Byte für Byte von rechts nach links übertragen, und der Rest des
Feldes wird mit Nullen aufgefüllt.
Von Binär (B) mit mehr als 4 Bytes in Alphanumerisch (A):
Der Wert wird Byte für Byte von links nach rechts übertragen. Je nach Länge des
Zielfeldes und der Anzahl der Bytes wird der Wert entweder abgeschnitten oder der
Rest des Feldes mit Leerzeichen aufgefüllt.
Von Datum (D) in Zeit (T):
Das Datum wird in Zeit umgesetzt, und zwar ausgehend von der Zeit
00:00:00:0.
Von Zeit (T) in Datum (D):
Die Zeitkomponente wird abgeschnitten und nur die Datumskomponente des Zeitfeldes
wird in das Datumsfeld übertragen.
Von Logisch (L), Datum (D), Zeit (T), Gleitkomma (F) in Alphanumerisch (A):
Der Wert wird in Anzeigeform umgesetzt und linksbündig übertragen.
Gleitkomma (F):
Wird ein Gleitkomma-Wert in ein alphanumerisches oder Unicode-Feld übertragen, das
zu kurz ist, wird die Mantisse entsprechend gekürzt.
Von Unicode (U) in Alphanumerisch (A):
Der Unicode-Wert wird anhand der Library ICU (International Components for
Unicode) entsprechend der voreingestellten (Default-)Codepage (Wert der
Systemvariablen *CODEPAGE) in alphanumerische
Zeichencodes umgesetzt. Je nach Länge des Zielfeldes und der Anzahl der Bytes wird
das Ergebnis entweder abgeschnitten oder der Rest des Feldes mit Leerzeichen
aufgefüllt. Wenn die Zeichen des Unicode-Wertes in der voreingestellten
(Default-)Codepage nicht definiert sind, wird ein Laufzeitfehler ausgegeben, oder an
die Stelle der Zeichen tritt je nach der Einstellung des Profil/Session-Parameters
CPCVERR das
Ersetzungszeichen.
Von Unicode (U) in Binär (B):
Der Wert wird Code Unit für Code Unit von links nach rechts verschoben. Je nach
Länge des Zielfeldes und der Anzahl der Bytes wird das Ergebnis entweder
abgeschnitten oder der Rest des Feldes mit Leerzeichen aufgefüllt. Die Länge des
binären Zielfeldes muss geradezahlig sein.
Von Alphanumerisch (A) in Unicode (U):
Der alphanumerische Wert wird unter Benutzung der Library ICU (International
Components for Unicode) von der voreingestellten (Default-)Codepage in einen
Unicode-Wert umgesetzt. Je nach Länge des Zielfeldes und der Anzahl der Code Units
wird das Ergebnis entweder abgeschnitten oder der Rest des Feldes mit Leerzeichen
aufgefüllt.
Von N, P, I und Binär (Länge 1-4) in Unicode (U):
Der Wert wird in ungepacktes Format konvertiert, aus dem dann ein alphanumerischer
Wert durch die Unterdrückung von führenden Nullen erhalten werden kann. Bei
negativen numerischen Werten wird das Vorzeichen in die hexadezimale Notation
Dx umgesetzt. Ein Dezimalpunkt im
numerischen Wert wird ignoriert. Alle Ziffern vor und nach dem Dezimalpunkt werden
als ein Ganzzahlwert (Integer) behandelt. Der Ergebniswert wird von alphanumerisch
in Unicode umgesetzt. Je nach Länge des Zielfeldes und der Anzahl der Code Units
wird das Ergebnis entweder abgeschnitten oder der Rest des Feldes mit Leerzeichen
aufgefüllt.
Von Binär (B) mit mehr als 4 Bytes in Unicode (U):
Der Wert wird Byte für Byte von links nach rechts verschoben. Je nach Länge des
Zielfeldes und der Anzahl der Bytes wird das Ergebnis entweder abgeschnitten oder
der Rest des Feldes mit Leerzeichen aufgefüllt. Die Länge des binären Ausgangsfeldes
muss geradzahlig sein.
Von L, D, T, F in U:
Die Werte werden in ein alphanumerisches Anzeigeformat konvertiert. Der
Ergebniswert wird von alphanumerisch in Unicode umgesetzt und linksbündig
ausgerichtet.
Wenn das Ausgangs- und Zielformat identisch sind, kann je nach der Länge und der Anzahl der Bytes (Format A und B) oder Code-Einheiten (Format U) das Ergebnis abgeschnitten oder mit Leerzeichen (Format A und U) oder führenden binären Nullen (Format B) aufgefüllt werden.
Siehe auch Dynamische Variablen benutzen.
Die folgenden Regeln gelten für das Abschneiden und Runden von Feldwerten:
Numerische Felder: vorangestellte Stellen dürfen nur abgeschnitten werden, falls ihr Wert Null ist. Stellen nach einem ausdrücklich angegebenen oder implizierten Komma (Dezimalpunkt) dürfen abgeschnitten werden.
Alphanumerische Felder: Nachfolgende Stellen dürfen abgeschnitten werden.
Bei Verwendung der Option ROUNDED wird die letzte Stelle im Feld
aufgerundet, falls die erste abgeschnittene Stelle größer/gleich 5 ist. Zur
Ergebnisgenauigkeit einer Division siehe auch Abschnitt Genauigkeit von Ergebnissen bei arithmetischen
Operationen.
Die folgende Tabelle zeigt Format/Länge von Ergebnisfeldern bei arithmetischen Operationen:
| I1 | I2 | I4 | N oder P | F4 | F8 | |
|---|---|---|---|---|---|---|
| I1 | I1 | I2 | I4 | P* | F4 | F8 |
| I2 | I2 | I2 | I4 | P* | F4 | F8 |
| I4 | I4 | I4 | I4 | P* | F4 | F8 |
| N oder P | P* | P* | P* | P* | F4 | F8 |
| F4 | F4 | F4 | F4 | F4 | F4 | F8 |
| F8 | F8 | F8 | F8 | F8 | F8 | F8 |
Auf Großrechnern wird Format/Länge F8 anstatt F4 für eine verbesserte Ergebnisgenauigkeit einer arithmetischen Operation benutzt.
P* ergibt sich aus der ganzzahligen Länge und Genauigkeit der einzelnen Operanden je nach Operation (siehe Abschnitt Genauigkeit von Ergebnissen bei arithmetischen Operationen.
Für Format I gelten die folgenden dezimalen Ganzzahl-Längen und möglichen Werte:
| Format/Länge | Dezimale Ganzzahl-Länge | Mögliche Werte |
|---|---|---|
I1 |
3 |
-128 bis 127 |
I2 |
5 |
-32768 bis 32767 |
I4 |
10 |
-2147483648 bis 2147483647 |
Folgende Themen werden behandelt:
Gleitkomma-Zahlen (Format F) werden ebenso wie Ganzzahlen (Format I) als Summe von Zweierpotenzen dargestellt, wohingegen ungepackte und gepackte Zahlen (Formate N und P) als Summe von Zehnerpotenzen dargestellt werden.
Bei ungepackten oder gepackten Zahlen ist die Position des Dezimalkommas fest. Bei Gleitkomma- Zahlen dagegen ist (wie der Name schon andeutet) die Position des Dezimalkommas "gleitend", d.h. seine Position ist nicht fest, sondern hängt vom tatsächlichen Wert der Zahl ab.
Gleitkomma-Zahlen sind unverzichtbar bei der Berechnung trigonometrischer und mathematischer Funktionen wie etwa Sinus oder Logarithmus.
Die Genauigkeit von Gleitkomma-Zahlen an sich ist begrenzt:
Bei einer Variablen mit Format/Länge F4 ist die Genauigkeit auf etwa 7 Stellen begrenzt.
Bei einer Variablen mit Format/Länge F8 ist die Genauigkeit auf 16 Stellen begrenzt.
Werte mit einer größeren Anzahl signifikanter Stellen lassen sich nicht exakt als Gleitkomma-Zahlen darstellen. Unabhängig von der Zahl zusätzlicher Vor- oder Nachkommastellen kann eine Gleitkomma-Zahl nur die ersten 7 bzw. 16 Stellen abdecken.
Eine Ganzzahl lässt sich nur exakt in einer Variablen mit Format/Länge F4 darstellen, wenn ihr absoluter Wert nicht größer als 2 24 -1 ist.
Wenn ein alphanumerischer, ungepackter numerischer oder gepackter numerischer Wert in Gleitkomma-Format umgesetzt wird (zum Beispiel bei einer Zuweisung), muss auch die Darstellungsform geändert werden, d.h. eine Summe von Zehnerpotenzen muss in eine Summe von Zweierpotenzen konvertiert werden.
Folglich lassen sich nur Zahlen, die als endliche Summe von Zweierpotenzen darstellbar sind, exakt darstellen; alle anderen Zahlen lassen sich nur näherungsweise darstellen.
Diese Zahl hat eine exakte Gleitkomma-Darstellung:
1.25 = 20 + 2-2
Diese Zahl ist eine periodische Gleitkomma-Zahl ohne exakte Darstellung:
1.2 = 20 + 2-3 + 2-4 + 2-7 + 2-8 + 2-11 + 2-12 + ...
Daher kann die Konvertierung von alphanumerischen, ungepackt numerischen oder gepackt numerischen Werten in Gleitkomma-Werte, und umgekehrt, zu kleineren Fehlern führen.
Anmerkung
Wenn Sie ein ganzzahliges, nicht gepacktes oder gepacktes Ergebnis einer
arithmetischen Operation (siehe Format/Länge
von Ergebnisfeldern bei arithmetischen Operationen ) in eine
Gleitkommadarstellung konvertiert werden soll, sollten Sie in Betracht ziehen, die
arithmetische Operation bereits im Gleitkommaformat durchzuführen, um die Genauigkeit zu
verbessern.
#F1 (F8) := 1 / 12 /* Result is +8.333330000000000E-02 #F2 (F8) := 1.0E0 / 12 /* Result is +8.333333333333333E-02
Aufgrund der unterschiedlichen Hardware-Architektur ist die Darstellung von Gleitkomma-Zahlen auf Großrechnern anders als auf anderen Plattformen. Dies erklärt, warum dieselbe Anwendung bei Gleitkomma-Berechnungen auf verschiedenen Plattformen möglicherweise geringfügig andere Ergebnisse liefert. Die entsprechende Darstellung bestimmt auch den möglichen Wertebereich für Gleitkomma-Variablen. Dieser beträgt (ca.):
±5.4 * 10-79 bis ±7.2 * 1075 für F4- und F8-Variablen.
Anmerkung
Die von Ihrem Taschenrechner verwendete Darstellung kann sich ebenfalls von der
Ihres Computers unterscheiden und die Ergebnisse für die gleiche Berechnung können daher
auch hier unterschiedlich sein.
Eine Potenzierungsoperation (operand1 **
operand2) wird intern berechnet als
EXP(operand2 *
LOG(operand1)) unter Verwendung der mathematischen
Funktionen EXP und LOG (siehe Mathematische
Systemfunktionen in der
Systemfunktionen-Dokumentation).
Mit Feldern der Formate D (Datum) und T (Time = Zeit) sind nur Addition, Subtraktion, Multiplikation und Division erlaubt. Multiplikation und Division sind nur bei Zwischenergebnissen von Addition und Subtraktion zulässig.
Datums-/Zeitwerte können addiert bzw. voneinander subtrahiert werden oder Ganzzahl-Werte (ohne Nachkommastellen) können zu/von Datums-/Zeitwerten addiert/subtrahiert werden. Solche ganzzahligen Werte können in Feldern der Formate N, P, I, D oder T enthalten sein.
Die Zwischenergebnisse einer solchen Addition oder Subtraktion können als Multiplikand oder Dividend in einer nachfolgenden Operation verwendet werden.
Von ganzzahligen Werten, die zu einem Datumswert addiert oder von einem Datumswert subtrahiert werden, wird angenommen, dass es sich um Tage handelt. Von ganzzahligen Werten, die zu einem Zeitwert addiert oder von einem Zeitwert subtrahiert werden, wird angenommen, dass es sich um Zehntelsekunden handelt.
Bei arithmetischen Operationen mit Datum und Zeit gelten gewisse Einschränkungen, und zwar aufgrund von Naturals interner Behandlung von Datums- und Zeitarithmetik, wie im folgenden erläutert.
Intern behandelt Natural eine arithmetische Operation mit Datums- bzw. Zeitvariablen wie folgt:
COMPUTE
result-field = operand1 +/-
operand2
|
Das obige Statement wird aufgelöst als:
intermediate-result = operand1
+/- operand2
result-field =
intermediate-result
Das heißt, zunächst berechnet Natural das Ergebnis der Addition/Subtraktion, und erst danach weist es das Ergebnis dem Ergebnisfeld zu.
Komplexere arithmetische Operationen werden nach dem gleichen Muster aufgelöst:
COMPUTE
result-field = operand1 +/-
operand2 +/- operand3 +/-
operand4
|
Das obige Statement wird aufgelöst als:
intermediate-result1 =
operand1 +/-
operand2
intermediate-result2 =
intermediate-result1 +/-
operand3
intermediate-result3 =
intermediate-result2 +/-
operand4
result-field =
intermediate-result3
Die Auflösung bei der Multiplikation und Division ist ähnlich wie die Auflösung bei der Addition und Subtraktion.
Das interne Format eines solchen Zwischenergebnisses (intermediate-result) hängt vom Format der einzelnen Operanden ab, wie die folgenden Tabellen zeigen.
Die folgende Tabelle zeigt das Format vom Zwischenergebnis einer Addition (intermediate-result = operand1 + operand2):
| Format von operand1 | Format von operand2 | Format von intermediate-result |
|---|---|---|
| D | D | Di |
| D | T | T |
| D | Di, Ti, N, P, I | D |
| T | D, T, Di, Ti, N, P, I | T |
| Di, Ti, N, P, I | D | D |
| Di, Ti, N, P, I | T | T |
| Di, N, P, I | Di | Di |
| Ti, N, P, I | Ti | Ti |
| Di | Ti, N, P, I | Di |
| Ti | Di, N, P, I | Ti |
Die folgende Tabelle zeigt das Format des Zwischenergebnisses einer Subtraktion (intermediate-result = operand1 - operand2):
| Format von operand1 | Format von operand2 | Format von intermediate-result |
|---|---|---|
| D | D | Di |
| D | T | Ti |
| D | Di, Ti, N, P, I | D |
| T | D, T | Ti |
| T | Di, Ti, N, P, I | T |
| Di, N, P, I | D | Di |
| Di, N, P, I | T | Ti |
| Di | Di, Ti, N, P, I | Di |
| Ti | D, T, Di, Ti, N, P, I | Ti |
| N, P, I | Di, Ti | P12 |
Die folgende Tabelle zeigt das Format des Zwischenergebnisses einer Multiplikation: (intermediate-result = operand1 * operand2) oder Division (intermediate-result = operand1 / operand2):
| Format von operand1 | Format von operand2 | Format von intermediate-result |
|---|---|---|
| D | D, Di, Ti, N, P, I | Di |
| D | T | Ti |
| T | D, T, Di, Ti, N, P, I | Ti |
| Di | T | Ti |
| Di | D, Di, Ti, N, P, I | Di |
| Ti | D | Di |
| Ti | Di, T, Ti, N, P, I | Ti |
| N, P, I | D, Di | Di |
| N, P, I | T, Ti | Ti |
Di ist ein Wert im internen Datumsformat; Ti ist ein Wert im internen Zeitformat; solche Werte können zwar in weiteren arithmetischen Datums-/Zeitoperationen verwendet werden, aber sie können keinem Ergebnisfeld vom Format D zugewiesen werden (siehe Zuweisungstabelle unten).
Bei komplexen arithmetischen Operationen, bei denen ein Zwischenergebnis im internen Format Di bzw. Ti als Operand für eine weitere Addition/Subtraktion/Multiplikation/Division verwendet wird, wird davon ausgegangen, dass es Format D bzw. T hat.
Die folgende Tabelle zeigt, welche Zwischenergebnisse intern welchen Ergebnisfeldern zugewiesen werden können (result-field = intermediate-result).
| Format von result-field | Format von intermediate-result | Zuweisung möglich |
|---|---|---|
| D | D, T | ja |
| D | Di, Ti, N, P, I | nein |
| T | D, T, Di, Ti, N, P, I | ja |
| N, P, I | D, T, Di, Ti, N, P, I | ja |
Ein Ergebnisfeld vom Format D oder T darf keinen negativen Wert enthalten.
COMPUTE DATE1 (D) = DATE2 (D) + DATE3 (D) COMPUTE DATE1 (D) = DATE2 (D) - DATE3 (D)
Diese Operationen sind nicht möglich, da das Zwischenergebnis der Addition bzw. Subtraktion Format Di hätte, und ein Wert vom Format Di keinem Ergebnisfeld vom Format D zugewiesen werden kann.
COMPUTE DATE1 (D) = TIME2 (T) - TIME3 (T) COMPUTE DATE1 (D) = DATE2 (D) - TIME3 (T)
Diese Operationen sind nicht möglich, da das Zwischenergebnis der Addition bzw. Subtraktion Format Ti hätte, und ein Wert vom Format Ti keinem Ergebnisfeld vom Format D zugewiesen werden kann.
COMPUTE DATE1 (D) = DATE2 (D) - DATE3 (D) + TIME3 (T)
Diese Operation ist möglich. Zunächst wird DATE3 von DATE2
subtrahiert, woraus sich ein Zwischenergebnis vom Format Di
ergibt; dann wird dieses Zwischenergebnis zu TIME3 hinzuaddiert, woraus sich
ein Zwischenergebnis vom Format T ergibt; und schließlich wird dieses zweite
Zwischenergebnis dem Ergebnisfeld DATE1 zugewiesen.
COMPUTE DATE1 (D) = DATE2 (D) + DATE3 (D) * 2 COMPUTE TIME1 (T) = TIME2 (T) - TIME3 (T) / 3
Diese Operationen sind nicht möglich, da die versuchte Multiplikation bzw. Division mit Datums-/Zeitfeldern und nicht mit Zwischenergebnissen durchgeführt wird.
COMPUTE DATE1 (D) = DATE2 (D) + (DATE3(D) - DATE4 (D)) * 2
Diese Operation ist möglich. Zunächst wird DATE4 von DATE3
subtrahiert, woraus sich ein Zwischenergebnis vom Format Di
ergibt; dann wird dieses Zwischenergebnis mit 2 multipliziert, woraus sich ein
Zwischenergebnis vom Format Di ergibt; dieses Zwischenergebnis
wird zu DATE2 addiert, woraus sich ein Zwischenergebnis vom Format D ergibt;
und schließlich wird dieses dritte Zwischenergebnis dem Ergebnisfeld DATE1
zugewiesen.
Wenn Sie einen Format-T-Wert einem Format-D-Feld zuweisen, müssen Sie dafür sorgen, dass der Zeitwert eine gültige Datumskomponente enthält.
Bei arithmetischen Operationen hat die Wahl der richtigen Feldformate starken Einfluss auf die Verarbeitungszeit:
Bei kaufmännischen Berechnungen empfiehlt es sich, nur Felder mit dem Format P (numerisch gepackt) zu verwenden. Die Anzahl der Stellen hinter dem Komma (Dezimalpunkt) sollte möglichst für alle Operanden einheitlich gewählt werden.
Bei wissenschaftlichen Berechnungen empfiehlt es sich, nur Felder mit dem Format F (Gleitkomma-Format) zu verwenden.
Werden die numerischen Formate N und P mit dem Format F vermischt, erfolgt intern eine Umsetzung in Format F; diese Umsetzung führt zu einer nicht unbeträchtlichen CPU-Beanspruchung. Daher sollte es möglichst vermieden werden, bei arithmetischen Operationen unterschiedliche Formate zu verwenden.
| Operation | Stellen vor dem Komma | Stellen nach dem Komma |
|---|---|---|
| Addition/Subtraktion | Fi + 1 oder Si + 1 (das jeweils größere) | Fd oder Sd (das jeweils größere) |
| Multiplikation | Fi + Si |
|
| Division | Fi + Sd | (siehe unten) |
| Potenzierung | 29 - Fd (Siehe Ausnahme unten) | Fd |
| Quadratwurzel |
|
|
Dabei ist:
| F | Erster Operand |
|---|---|
| S | Zweiter Operand |
| R | Ergebnis |
| i | Stellen vor dem Komma (Dezimalpunkt) |
| d | Stellen nach dem Komma (Dezimalpunkt) |
| MAXPREC | Maximale Anzahl von Nachkommastellen entsprechend der Festlegung mit der
Option MAXPREC des Systemkommandos COMPOPT oder
mit dem Subparameter MAXPREC des Profilparameters CMPO. Der
Standrdwertwert ist 7.
|
Wenn die Hochzahl eine oder mehrere Stellen hinter dem Komma (Dezimalpunkt) aufweist, wird die Potenzierung intern im Gleitkomma-Format ausgeführt und das Ergebnis hat ebenfalls Gleitkomma-Format. Weitere Informationen siehe Abschnitt Arithmetische Operationen mit Gleitkomma-Zahlen.
Die Genauigkeit des Ergebnisses einer Division hängt davon ab, ob ein Ergebnisfeld vorhanden ist oder nicht:
Ist ein Ergebnisfeld vorhanden, ist die Genauigkeit: Fd oder
Rd (das jeweils größere) *.
Ist kein Ergebnisfeld vorhanden, ist die Genauigkeit: Fd oder
Sd (das jeweils größere) *.
* Bei Verwendung der ROUNDED-Option erhöht sich die
Ergebnisgenauigkeit intern um eine Stelle, bevor das Ergebnis tatsächlich gerundet wird,
solange der Wert der Option MAXPREC dabei nicht überschritten
wird.
Ein Ergebnisfeld ist vorhanden (bzw. wird als vorhanden angenommen) in einem
COMPUTE- und DIVIDE-Statement sowie in einer logischen
Bedingung, in der die Division hinter dem Vergleichsoperator steht (z.B.: IF #A =
#B / #C THEN ...).
Ein Ergebnisfeld wird als nicht vorhanden angenommen in einer logischen Bedingung, in
der die Division vor dem Vergleichsoperator steht (z.B.: IF #B / #C = #A THEN
...).
Wenn Dividend und Divisor Ganzzahlen sind und mindestens eine davon eine Variable ist,
dann ist auch das Divisionsergebnis eine Ganzzahl (unabhängig von der Genauigkeit des
Ergebnisfeldes sowie der Verwendung der ROUNDED-Option).
Die Genauigkeit von arithmetischen Ausdrücken, zum Beispiel #A / (#B * #C) + #D *
(#E - #F + #G), wird von der Auswertung der Ergebnisse von arithmetischen
Operationen in ihrer Verarbeitungsreihenfolge hergeleitet. Weitere Informationen zu
arithmetischen Ausdrücken siehe arithmetic-expression in der Beschreibung des
COMPUTE-Statements.
Bei einer Addition, Subtraktion, Multiplikation oder Division kann ein Fehler auftreten, wenn das Ergebnis (insgesamt, d.h. vor und nach dem Komma) mehr als 31 Stellen hat.
Bei einer Potenzierung erhalten Sie unter einer der folgenden Bedingungen einen Fehler:
wenn die Basis gepacktes Format mit Dezimalstellen (zum Beispiel P3.2) hat und der Exponent größer als 16 ist;
wenn die Basis Gleitkomma-Format hat und das Ergebnis größer ist als ca. 7 * 1075.
Grundsätzlich gelten folgende Regeln:
Alle Skalar-Operationen können auf Array-Elemente angewandt werden, die aus einer einzigen Ausprägung bestehen.
Wenn eine Variable mit einem konstanten Wert definiert ist (z.B. #FIELD (I2)
CONSTANT <8>), dann wird der Wert der Variablen bei der Kompilierung
zugewiesen, und die Variable wird als Konstante behandelt. Falls eine solche Variable
in einem Array-Index verwendet wird, bedeutet dies, dass die betreffende Dimension
eine bestimmte Anzahl von Ausprägungen hat.
Bei einer Zuweisung bzw. einem Vergleich zwischen zwei Arrays mit unterschiedlich vielen Dimensionen wird angenommen, dass die "fehlende" Dimension in dem Array mit weniger Dimensionen (1:1) ist.
Beispiel: Wenn das Array #ARRAY1 (1:2) dem Array #ARRAY2
(1:2,1:2) zugewiesen wird, wird für #ARRAY1 angenommen, dass es
#ARRAY1 (1:1,1:2) ist.
Folgende Themen werden behandelt:
Die erste, zweite und dritte Dimension eines Arrays werden wie folgt definiert:
| Dimensionen | Eigenschaften |
|---|---|
| 3 | #a3 (3. Dim., 2. Dim., 1. Dim.) |
| 2 | #a2 (2. Dim., 1. Dim.) |
| 1 | #a1 (1. Dim.) |
Wenn Sie einen Array-Bereich einem anderen Array-Bereich zuweisen, erfolgt die Zuweisung Element für Element.
Beispiel:
DEFINE DATA LOCAL 1 #ARRAY(I4/1:5) INIT <10,20,30,40,50> END-DEFINE * MOVE #ARRAY(2:4) TO #ARRAY(3:5) /* is identical to /* MOVE #ARRAY(2) TO #ARRAY(3) /* MOVE #ARRAY(3) TO #ARRAY(4) /* MOVE #ARRAY(4) TO #ARRAY(5) /* /* #ARRAY contains 10,20,20,20,20
Wenn Sie eine einzelne Ausprägung einem Array-Bereich zuweisen, wird jedes Element des Bereiches mit dem Wert der einzelnen Ausprägung gefüllt. (Bei einer mathematischen Funktion wird jedes Element des Bereiches mit dem Ergebnis der Funktion gefüllt.)
Bevor eine Zuweisung ausgeführt wird, werden die einzelnen Dimensionen der betroffenen Arrays miteinander verglichen, um zu prüfen, ob sie eine der unten aufgeführten Bedingungen erfüllen.
Die Dimensionen werden dabei unabhängig voneinander verglichen; d.h. die 1. Dimension des einen Arrays wird mit der 1. Dimension des anderen Arrays verglichen, die 2. Dimension des einen Arrays wird mit der 2. Dimension des anderen Arrays verglichen, und die 3. Dimension des einen Arrays wird mit der 3. Dimension des anderen Arrays verglichen.
Die Zuweisung von Werten eines Arrays an ein anderes Array ist nur unter einer der folgenden Bedingungen erlaubt:
Die zwei verglichenen Dimensionen haben die gleiche Anzahl von Ausprägungen.
Die zwei verglichenen Dimensionen haben beide eine unbestimmte Anzahl von Ausprägungen.
Die Dimension, die einer anderen Dimension zugewiesen wird, besteht aus einer einzelnen Ausprägung.
Das folgende Programm zeigt, welche Zuweisungen zwischen Arrays möglich sind.
DEFINE DATA LOCAL 1 A1 (N1/1:8) 1 B1 (N1/1:8) 1 A2 (N1/1:8,1:8) 1 B2 (N1/1:8,1:8) 1 A3 (N1/1:8,1:8,1:8) 1 I (I2) INIT <4> 1 J (I2) INIT <8> 1 K (I2) CONST <8> END-DEFINE * COMPUTE A1(1:3) = B1(6:8) /* allowed COMPUTE A1(1:I) = B1(1:I) /* allowed COMPUTE A1(*) = B1(1:8) /* allowed COMPUTE A1(2:3) = B1(I:I+1) /* allowed COMPUTE A1(1) = B1(I) /* allowed COMPUTE A1(1:I) = B1(3) /* allowed COMPUTE A1(I:J) = B1(I+2) /* allowed COMPUTE A1(1:I) = B1(5:J) /* allowed COMPUTE A1(1:I) = B1(2) /* allowed COMPUTE A1(1:2) = B1(1:J) /* NOT ALLOWED (NAT0631) COMPUTE A1(*) = B1(1:J) /* NOT ALLOWED (NAT0631) COMPUTE A1(*) = B1(1:K) /* allowed COMPUTE A1(1:J) = B1(1:K) /* NOT ALLOWED (NAT0631) * COMPUTE A1(*) = B2(1,*) /* allowed COMPUTE A1(1:3) = B2(1,I:I+2) /* allowed COMPUTE A1(1:3) = B2(1:3,1) /* NOT ALLOWED (NAT0631) * COMPUTE A2(1,1:3) = B1(6:8) /* allowed COMPUTE A2(*,1:I) = B1(5:J) /* allowed COMPUTE A2(*,1) = B1(*) /* NOT ALLOWED (NAT0631) COMPUTE A2(1:I,1) = B1(1:J) /* NOT ALLOWED (NAT0631) COMPUTE A2(1:I,1:J) = B1(1:J) /* allowed * COMPUTE A2(1,I) = B2(1,1) /* allowed COMPUTE A2(1:I,1) = B2(1:I,2) /* allowed COMPUTE A2(1:2,1:8) = B2(I:I+1,*) /* allowed * COMPUTE A3(1,1,1:I) = B1(1) /* allowed COMPUTE A3(1,1,1:J) = B1(*) /* NOT ALLOWED (NAT0631) COMPUTE A3(1,1,1:I) = B1(1:I) /* allowed COMPUTE A3(1,1:2,1:I) = B2(1,1:I) /* allowed COMPUTE A3(1,1,1:I) = B2(1:2,1:I) /* NOT ALLOWED (NAT0631) END
Grundsätzlich gilt Folgendes: Wenn mehrdimensionale Arrays miteinander verglichen werden, werden die einzelnen Dimensionen unabhängig voneinander behandelt; d.h. die 1. Dimension des einen Arrays wird mit der 1. Dimension des anderen Arrays verglichen, die 2. Dimension des einen Arrays wird mit der 2. Dimension des anderen Arrays verglichen, und die 3. Dimension des einen Arrays wird mit der 3. Dimension des anderen Arrays verglichen.
Der Vergleich zweier Array-Dimensionen ist nur unter einer der folgenden Bedingungen erlaubt:
Die zwei verglichenen Dimensionen haben die gleiche Anzahl von Ausprägungen.
Die zwei verglichenen Dimensionen haben beide eine unbestimmte Anzahl von Ausprägungen.
Alle Dimensionen des einen Arrays bestehen jeweils aus einer einzelnen Ausprägung.
Das folgende Programm zeigt, welche Vergleiche zwischen Arrays möglich sind.
DEFINE DATA LOCAL 1 A3 (N1/1:8,1:8,1:8) 1 A2 (N1/1:8,1:8) 1 A1 (N1/1:8) 1 I (I2) INIT <4> 1 J (I2) INIT <8> 1 K (I2) CONST <8> END-DEFINE * IF A2(1,1) = A1(1) THEN IGNORE END-IF /* allowed IF A2(1,1) = A1(I) THEN IGNORE END-IF /* allowed IF A2(1,*) = A1(1) THEN IGNORE END-IF /* allowed IF A2(1,*) = A1(I) THEN IGNORE END-IF /* allowed IF A2(1,*) = A1(*) THEN IGNORE END-IF /* allowed IF A2(1,*) = A1(I -3:I+4) THEN IGNORE END-IF /* allowed IF A2(1,5:J) = A1(1:I) THEN IGNORE END-IF /* allowed IF A2(1,*) = A1(1:I) THEN IGNORE END-IF /* NOT ALLOWED(NAT0629) IF A2(1,*) = A1(1:K) THEN IGNORE END-IF /* allowed * IF A2(1,1) = A2(1,1) THEN IGNORE END-IF /* allowed IF A2(1,1) = A2(1,I) THEN IGNORE END-IF /* allowed IF A2(1,*) = A2(1,1:8) THEN IGNORE END-IF /* allowed IF A2(1,*) = A2(I,I -3:I+4) THEN IGNORE END-IF /* allowed IF A2(1,1:I) = A2(1,I+1:J) THEN IGNORE END-IF /* allowed IF A2(1,1:I) = A2(1,I:I+1) THEN IGNORE END-IF /* NOT ALLOWED(NAT0629) IF A2(*,1) = A2(1,*) THEN IGNORE END-IF /* NOT ALLOWED(NAT0629) IF A2(1,1:I) = A1(2,1:K) THEN IGNORE END-IF /* NOT ALLOWED(NAT0629) * IF A3(1,1,*) = A2(1,*) THEN IGNORE END-IF /* allowed IF A3(1,1,*) = A2(1,I -3:I+4) THEN IGNORE END-IF /* allowed IF A3(1,*,I:J) = A2(*,1:I+1) THEN IGNORE END-IF /* allowed IF A3(1,*,I:J) = A2(*,I:J) THEN IGNORE END-IF /* allowed END
Wenn Sie zwei Array-Bereiche miteinander vergleichen, beachten Sie bitte, dass die folgenden zwei Ausdrücke zu unterschiedlichen Ergebnissen führen:
#ARRAY1(*) NOT EQUAL #ARRAY2(*) NOT #ARRAY1(*) = #ARRAY2(*)
Beispiel:
IF #ARRAY1(1:2) NOT EQUAL #ARRAY2(1:2)
Dies entspricht:
IF (#ARRAY1(1) NOT EQUAL #ARRAY2(1)) AND (#ARRAY1(2) NOT EQUAL #ARRAY2(2))
Bedingung A ist also erfüllt, wenn die erste Ausprägung von #ARRAY1
ungleich der ersten Ausprägung von #ARRAY2 ist und die zweite
Ausprägung von #ARRAY1 ungleich der zweiten Ausprägung von
#ARRAY2 ist.
IF NOT #ARRAY1(1:2) = #ARRAY2(1:2)
Dies entspricht:
IF NOT (#ARRAY1(1)= #ARRAY2(1) AND #ARRAY1(2) = #ARRAY2(2))
Dies wiederum entspricht:
IF (#ARRAY1(1) NOT EQUAL #ARRAY2(1)) OR (#ARRAY1(2) NOT EQUAL #ARRAY2(2))
Bedingung B ist also erfüllt, wenn entweder die erste Ausprägung von
#ARRAY1 ungleich der ersten Ausprägung von #ARRAY2 ist
oder die zweite Ausprägung von #ARRAY1 ungleich der zweiten
Ausprägung von #ARRAY2 ist.
Eine allgemeine Regel zu Arrays lautet, dass die Anzahl der Ausprägungen der entsprechenden Dimensionen gleich sein muss.
Das folgende Beispiel veranschaulicht diese Regel:
#c(2:3,2:4) := #a(3:4,1:3) + #b(3:5)
Mit anderen Worten:
| Array | Dimension | Anzahl der Ausprägungen | Bereich |
|---|---|---|---|
| #c | 2. | 2 | 2:3 |
| #c | 1. | 3 | 2:4 |
| #a | 2. | 2 | 3:4 |
| #a | 1. | 3 | 1:3 |
| #b | 1. | 3 | 3:5 |
Die Operation wird Element für Element durchgeführt
Anmerkung
Eine arithmetische Operation einer unterschiedlichen Anzahl von Dimensionen ist
zulässig.
Für das obige Beispiel werden die folgenden Operationen ausgeführt:
#c(2,2) := #a(3,1) + #b(3) #c(2,3) := #a(3,2) + #b(4) #c(2,4) := #a(3,3) + #b(5) #c(3,2) := #a(4,1) + #b(3) #c(3,3) := #a(4,2) + #b(4) #c(3,4) := #a(4,3) + #b(5)
In arithmetischen Operationen (in COMPUTE-, ADD- oder MULTIPLY-Statements) können Array-Bereiche auf folgende
Arten verwendet werden. In den Beispielen 1 - 4 muss die Anzahl der Ausprägungen der
entsprechenden Dimensionen gleich sein.
range + range =
range.
Die Addition wird Element für Element ausgeführt.
range * range =
range.
Die Multiplikation wird Element für Element ausgeführt.
scalar + range =
range.
Der Skalarwert wird zu jedem Element des Bereichs addiert.
range * scalar =
range.
Jedes Element des Bereichs wird mit dem Skalarwert multipliziert.
range + scalar =
scalar.
Jedes Element des Bereichs wird zum Skalarwert addiert und das Ergebnis im Skalar ausgegeben.
scalar * range =
scalar2.
Der Skalarwert wird mit jedem Element des Arrays multipliziert und das Ergebnis in
scalar2 ausgegeben.
Weil, wie aus den Beispielen 1 - 4 hervorgeht, bei arithmetischen Operationen keine Zwischenergebnisse erzeugt werden, muss das errechnete Ergebnis (siehe Format/Länge von Ergebnisfeldern bei arithmetischen Operationen) dasselbe Format haben wie der Ergebnis-Operand (die Formate P und N gelten als gleiche Formate).
Beispiel:
DEFINE DATA LOCAL 1 #ARRAYI4(I4/1:5) 1 #ARRAYP5(P5/1:5) END-DEFINE * #ARRAYI4(*) := #ARRAYP5(*) + 1 /* NOT ALLOWED(NAT0294)
Weil, wie aus den obigen Beispielen hervorgeht, bei arithmetischen Operationen keine Zwischenergebnisse erzeugt werden, wird das Ergebnis von sich überlappenden Indexbereichen Element für Element berechnet.
Beispiel:
DEFINE DATA LOCAL 1 #ARRAY(I4/1:5) INIT <10,20,30,40,50> END-DEFINE * #ARRAY(3:5) := #ARRAY(2:4) + 1 /* is identical to /* #ARRAY(3) := #ARRAY(2) + 1 /* #ARRAY(4) := #ARRAY(3) + 1 /* #ARRAY(5) := #ARRAY(4) + 1 /* /* #ARRAY contains 10,20,21,22,23