Zum Inhalt springen
14. Aug. 2026·8 Min. Lesezeit

COBOL-COMP-3-Migration ohne einen Cent Verlust

Eine COBOL-COMP-3-Migration scheitert, wenn Skala, Vorzeichen, Rundung oder ungültige Bytes abweichen. Modellieren und prüfen Sie jeden Betrag.

COBOL-COMP-3-Migration ohne einen Cent Verlust

Für die Neuentwicklung eines Geldsystems gibt es genau eine Abnahmegrenze: Dieselbe gültige Eingabe muss denselben Betrag, dasselbe Vorzeichen, denselben Status und dieselbe gespeicherte Darstellung erzeugen, sofern diese Darstellung weiterhin Teil einer Schnittstelle ist. Eine Abweichung von einem Cent ist kein Schönheitsfehler. Über eine Million Datensätze kann sie eine Hauptbuchsumme, eine Ausnahmewarteschlange, eine Zinsstufe oder die Datei verändern, die ein nachgelagertes Programm akzeptiert.

Die gefährliche Annahme lautet, ein COBOL-Feld lasse sich einem Typ in einer modernen Sprache zuordnen. Das stimmt nicht. Seine Bedeutung ergibt sich aus PICTURE, USAGE, Compileroptionen, Rechenanweisungen, Zielfeldern, Dateilayout und bisweilen aus jahrzehntelang geduldeten fehlerhaften Daten. PIC S9(7)V99 COMP-3 beschreibt einen vorzeichenbehafteten ganzzahligen Koeffizienten mit einer angenommenen Skala von zwei sowie einen gepackten Speichervertrag. Wer das als gewöhnliche Zahl behandelt, verwirft mindestens die Hälfte dieser Informationen.

Ich habe erlebt, wie Teams länger über decimal gegen double diskutierten, als den MOVE zu verfolgen, der Nachkommastellen tatsächlich abschneidet. Diese Diskussion beginnt zu spät. Rekonstruieren Sie zuerst den numerischen Vertrag. Wählen Sie danach eine Zieldarstellung, die ihn erzwingen kann, und führen Sie beide Systeme mit demselben Verkehr aus, bis jede Abweichung erklärt ist.

Die PICTURE-Klausel gehört zum Wert

Die PICTURE-Klausel bestimmt Ziffernzahl, Skala, Vorzeichenfähigkeit und mitunter Skalierungsstellen, die keinen Speicher belegen. Nichts davon dient nur der Formatierung.

Betrachten Sie diese Deklarationen:

01  INVOICE-AMOUNT      PIC S9(7)V99 COMP-3.
01  TAX-RATE            PIC S9(3)V9(4) COMP-3.
01  WHOLE-DOLLARS       PIC S9(9) COMP-3.
01  SMALL-RATIO         PIC SV9(6) COMP-3.

V ist ein angenommener Dezimalpunkt. Weder im Arbeitsspeicher noch auf dem Datenträger gibt es dafür ein Byte. INVOICE-AMOUNT speichert neun Dezimalziffern plus Vorzeichen, und der Koeffizient 123456789 bedeutet 1234567.89. TAX-RATE verwendet Skala vier. WHOLE-DOLLARS hat Skala null. SMALL-RATIO hat keine ganzzahligen Stellen, der Koeffizient 123456 bedeutet also 0.123456.

Ein Migrationsinventar sollte für jedes elementare numerische Element mindestens (signed, precision, scale, usage, byte length) festhalten. Bewahren Sie daneben die ursprüngliche Deklaration und das übergeordnete Datensatzlayout auf. Copybooks verwenden REDEFINES, OCCURS, Bedingungsnamen und Gruppenverschiebungen. Deshalb lässt sich ein Feld nicht immer unabhängig von benachbarten Bytes deuten.

Das Symbol P braucht eine eigene Behandlung. Es beschreibt angenommene Skalierungsstellen, die nicht gespeichert werden. Die Dokumentation zu IBM Enterprise COBOL nennt Beispiele wie PPP999, dessen gespeicherte Ziffern Werte von null bis .000999 darstellen, sowie S999PPP, dessen von null verschiedene Werte in Tausenderschritten fortschreiten. Ein Mapper, der nur gespeicherte Ziffern zählt, verfehlt die arithmetische Skala. Leiten Sie DECIMAL(p,s) in der Datenbank nicht aus der Bytelänge ab.

Erzeugen Sie einen maschinenlesbaren Katalog statt einer Tabelle, die sich vom Code entfernt. Ein brauchbarer Eintrag sieht so aus:

{
  "qualifiedName": "CLAIM-REC.PAID-AMOUNT",
  "picture": "S9(7)V99",
  "usage": "COMP-3",
  "bytes": 5,
  "precision": 9,
  "scale": 2,
  "signed": true,
  "storage": "packed-decimal"
}

Dieses Artefakt bildet den Anfang des Vertrags für die Neuentwicklung. Es erkennt auch einen verbreiteten Parserfehler: Neun Ziffern in gepackter Dezimaldarstellung brauchen fünf Bytes, weil das letzte Halbbyte das Vorzeichen enthält.

Lösen Sie Aliase auf, bevor Sie die Zuständigkeit festlegen. Ein REDEFINES-Zweig kann dieselben fünf Bytes bei einem Transaktionstyp als Betrag und bei einem anderen als Füllbereich oder Datum behandeln. Der Diskriminator, der den Zweig auswählt, gehört zum numerischen Vertrag. Wenn die neue Einleseschicht jeden möglichen Zweig sofort dekodiert, kann sie gültige Datensätze ablehnen, weil Bytes in einem Layout numerisch und in einem anderen textuell sind. Erfassen Sie die steuernde Bedingung, nicht nur überlappende Offsets.

Gruppenoperationen erfordern aus dem gegenteiligen Grund Aufmerksamkeit. MOVE OLD-GROUP TO NEW-GROUP kopiert Bytes, ohne Umwandlungsregeln für elementare numerische Felder anzuwenden. Eine feldweise Objektzuordnung kann Vorzeichen normalisieren, Füllnibbles ändern oder ein Feld dekodieren, das die Quelle nie ausgewertet hat. Ordnen Sie jede Verwendung als Byte- oder numerische Operation ein, bevor Sie ein typisiertes Objekt für gleichwertig erklären.

COMP-3-Bytes brauchen einen Decoder, keinen Cast

Gepackte Dezimalzahlen speichern zwei Dezimalziffern pro Byte. Nur das niedrige Nibble des letzten Bytes trägt das Vorzeichen. Die Ziellaufzeit muss diese Nibbles an jeder externen Grenze ausdrücklich prüfen und dekodieren.

Für PIC S9(5)V99 COMP-3 kann der Wert -12345.67 mit dem Koeffizienten -1234567 so erscheinen:

12 34 56 7D

Lesen Sie die Nibbles als 1 2 3 4 5 6 7 D. Die ersten sieben sind Ziffern. Das abschließende D ist negativ. Ein üblicher positiver Wert endet mit C; vorzeichenlose gepackte Daten enden oft mit F. In echten Systemen können abhängig von Compileroptionen und Erzeugungspfad weitere Vorzeichencodes vorkommen. Darum braucht der Decoder eine erklärte Richtlinie statt einer freizügigen Hexadezimalumwandlung.

Die Bytelänge für n gespeicherte Dezimalziffern beträgt floor(n / 2) + 1. Bei gerader Ziffernzahl ist das erste Nibble ein Füllwert. Auch dieser Wert zählt bei der Prüfung. IBM dokumentiert, dass NUMCHECK(PAC) gepackte Ziffern und Vorzeichen prüft, wenn Felder als Sender dienen, und bei gerader Ziffernzahl auch die ungenutzten Bits. Ihr neuer Decoder muss entscheiden, ob fehlerhafte Füllbits den Datensatz ablehnen, in Quarantäne schicken oder einer ausdrücklich dokumentierten Alttoleranz folgen.

Dieser Pseudocode macht die Grenze sichtbar:

decodePacked(bytes, precision, scale, signed):
    nibbles = splitEachByte(bytes)
    signNibble = nibbles.removeLast()
    if precision is even:
        require nibbles.removeFirst() == 0
    require count(nibbles) == precision
    require every nibble is between 0 and 9
    sign = decodeSign(signNibble, signed, configuredSignPolicy)
    coefficient = sign * decimalDigitsToInteger(nibbles)
    return FixedDecimal(coefficient, scale)

Halten Sie den Koeffizienten als ganze Zahl und die Skala als Metadatum. Dadurch bleibt 123.40 von einem skalafreien Gleitkommawert unterscheidbar, selbst wenn die Anzeige später 123.4 ausgibt. Außerdem kann ein Encoder Datensätze mit fester Breite exakt reproduzieren.

Schreiben Sie den Encoder unabhängig und testen Sie dann encode(decode(bytes)) für jede gültige kanonische Eingabe. Prüfen Sie ebenfalls nicht kanonische Eingaben, die Ihre Richtlinie zulässt. Numerische Gleichheit kann erlauben, dass der Encoder ein positives F zu C normalisiert. Byteparität scheitert jedoch, wenn ein externer Verbraucher die ursprüngliche Form erwartet. Falls genaue Rundläufe nötig sind, speichern Sie den ursprünglichen Vorzeichencode oder das komplette Rohfeld neben der dekodierten Zahl.

Lassen Sie den Decoder nach einem Fehler nicht null zurückgeben. Manche Umwandlungsbibliotheken tun das, wenn niemand den Parsestatus prüft, und machen aus fehlerhaftem Geld einen gültigen Betrag. Geben Sie ein markiertes Ergebnis zurück, das den Aufrufer zur Behandlung gültiger, ungültiger und aufgeschobener Zustände zwingt. Das Typsystem sollte versehentliches Rechnen mit nicht dekodierten Bytes erschweren.

Negative null verdient einen Test. Gepackte oder gezonte Eingaben können Nullziffern mit negativem Vorzeichen tragen. Die meisten Geschäftsrechnungen behandeln -0.00 und 0.00 als gleich, doch eine bytegenaue Ausgabedatei, ein Audit-Feed oder eine vorzeichenabhängige Verzweigung vielleicht nicht. Legen Sie fest, ob die Dekodierung normalisiert, ein Vorzeichenflag behält oder die Rohbytes für den Rundlauf aufbewahrt. Schweigen ist keine Richtlinie.

Signed Overpunch ist ein anderer Speichervertrag

Signed Overpunch gehört zu gezonten Dezimalzahlen oder numerischen DISPLAY-Daten, nicht zu COMP-3, obwohl beide Formate ein Vorzeichen in einer Ziffernposition unterbringen. Wer beide verwechselt, beschädigt Werte und erzeugt dennoch glaubwürdig wirkende Zeichen.

Bei gezonten EBCDIC-Dezimalzahlen belegt jede Ziffer ein Byte. Bei nachgestelltem Overpunch trägt das hohe Nibble des letzten Ziffernbytes das Vorzeichen und das niedrige Nibble die letzte Ziffer. Ein positives 123 kann mit einem Byte enden, dessen Zonennibble positiv bedeutet; -123 verwendet eine negative Zone. Als Zeichen umgewandelt können diese Bytemuster unter bekannten Overpunch-Tabellen als Buchstaben oder Klammern erscheinen. Diese sichtbare Form ist eine Kodierungskonvention, nicht der Zahlenwert.

Felddeklaration und Dateikodierung müssen zusammenbleiben. Ein ASCII-Parser kann aus 12L nicht sicher eine negative Drei ableiten, ohne die erzeugende Overpunch-Tabelle zu kennen. Auch eine Umwandlung von EBCDIC nach Unicode vor der numerischen Dekodierung kann die ursprünglichen Zonenbits zerstören oder so abbilden, dass ein allgemeiner Dezimalparser sie ablehnt.

Dekodieren Sie in dieser Reihenfolge:

  1. Schneiden Sie den Datensatz nach seinem Bytelayout, bevor eine Zeichenumwandlung Offsets verändert.
  2. Wenden Sie die festgelegte EBCDIC-Codeseite auf normale Textfelder an, schicken Sie numerische DISPLAY-Bytes aber an einen Decoder für gezonte Dezimalzahlen.
  3. Prüfen Sie jede Ziffernzone und die zulässige Vorzeichenmenge.
  4. Geben Sie dieselbe Darstellung aus Koeffizient und Skala zurück, die auch gepackte Dezimalzahlen verwenden.
  5. Bewahren Sie Rohbytes abgelehnter Datensätze auf, damit ein Operator den tatsächlichen Erzeuger erkennen kann.

SIGN IS LEADING, SIGN IS TRAILING und SIGN IS SEPARATE verändern diesen Vertrag. Ein separates Vorzeichen verbraucht eine eigene Zeichenposition; ein Overpunch-Vorzeichen nicht. Copybook-Parser, die alle vorzeichenbehafteten DISPLAY-Elemente auf eine Regel reduzieren, verschieben Datensatzgrenzen oder verlieren das Vorzeichen.

Eine Vereinheitlichung ist sinnvoll: Gepackte und gezonte Dezimalzahlen können nach der Dekodierung dieselbe Domänendarstellung nutzen. Den Grenzdecoder dürfen sie nicht teilen. Getrennte Decoder halten Speicherregeln aus Geschäftsrechnungen heraus und liefern für fehlerhafte Daten präzise Meldungen wie invalid packed digit at byte 3 statt number format error.

Exakte Dezimaltypen reichen allein nicht aus

Verwenden Sie ganzzahlige Koeffizienten, Festkommatypen oder Datenbank-Numerics für Geld. Leiten Sie COBOL-Dezimalwerte niemals durch binäre Gleitkommatypen, auch nicht vorübergehend als JSON-Zahl oder Tabellenzelle, denn viele Dezimalbrüche haben keine exakte Binärdarstellung.

Die Zielabbildung muss sich nach beobachteten Operationen und Wertebereich richten. Ein Feld wie S9(7)V99 COMP-3 darf erst nach dem Nachweis, dass Zwischenprodukte passen, einen vorzeichenbehafteten 64-Bit-Koeffizienten mit Skala zwei verwenden. Werte nahe 31 Dezimalstellen brauchen meist einen Koeffizienten mit beliebiger Genauigkeit. Geldwerte gehören in der Datenbank nach Tests des Rundungs- und Überlaufverhaltens in DECIMAL(p,s) oder NUMERIC(p,s). Wire- und JSON-Grenzen sollten Dezimalstrings mit eindeutigen Skalaregeln übertragen, damit Verbraucher sie nicht in Gleitkommawerte umwandeln.

Go hat keinen eingebauten Festkommadezimaltyp mit beliebiger Genauigkeit. Ein Team kann Cents in int64 speichern, wenn die vollständige Rechnung den Wertebereich nachweist, oder math/big.Int als Koeffizienten mit kontrollierter Skala kapseln. Rust kann geprüfte Ganzzahlarithmetik oder eine Dezimalbibliothek verwenden, deren Genauigkeit und Rundungsarten untersucht wurden. TypeScripts number ist binäres Gleitkomma; verwenden Sie Strings, skaliertes bigint oder eine geprüfte Dezimalimplementierung für Geld. PostgreSQL numeric verarbeitet Dezimalwerte exakt, doch die Anwendung bestimmt weiterhin den Zeitpunkt der Skalenreduktion.

Führen Sie den Bereichsnachweis mit Zwischenwerten, nicht nur mit gespeicherten Feldern. Ein neunstelliger Betrag multipliziert mit einer siebenstelligen Rate kann vor Division oder Neuskalierung viel mehr als neun Stellen brauchen. COBOL kann den Zwischenwert mit einer durch Arithmetikregeln und Compileroptionen bestimmten Genauigkeit halten. int64 im Ziel kann alle Eingabefelder aufnehmen und trotzdem bei ihrem Produkt überlaufen.

Unterscheiden Sie außerdem Speicherskala und Geschäftseinheit. PIC S9(7)V99 bedeutet oft Währung in Cents, doch die Deklaration verrät weder die Währung noch, ob die Rechnung Centbruchteile erlaubt oder ob der Wert Steuer, Rate oder Betrag ist. Bilden Sie diese Bedeutungen in Domänentypen ab, sobald das Programm sie erkennen lässt. Money, Rate und Quantity dürfen nicht allein deshalb addiert oder multipliziert werden, weil alle einen Dezimalkoeffizienten haben.

Verwenden Sie das Datenbankschema nicht als erste und einzige Spezifikation. Eine im Lauf der Jahre verbreiterte Spalte kann Werte aufnehmen, die das COBOL-Feld nicht speichern kann. Eine engere Spalte kann zeigen, dass eine Schnittstelle schon vor dem Speichern rundet. Ordnen Sie Quelldeklarationen, Anweisungen, Datensatzlayouts und Datenbankbedingungen als einen numerischen Fluss zu.

Definieren Sie Rechen-APIs um die Domäne, statt überall ein allgemeines Dezimalobjekt freizugeben. Ein Betrag kann einen anderen Betrag derselben Einheit addieren. Eine Rate kann einen Betrag multiplizieren und einen Zwischenwert mit höherer Skala erzeugen. Eine Aufteilung braucht eine erklärte Restregel, weil 10.00 durch drei geteilt nicht jedem Empfänger dieselben Cents geben kann. Solche Einschränkungen machen Geschäftsregeln sichtbar, die Entwickler mit einer freizügigen Dezimalbibliothek umgehen könnten.

Auch Serialisierung braucht einen Vertrag. Bestimmen Sie, ob Skala zwei immer 12.30 ausgibt, ob Pluszeichen erlaubt sind, ob Exponentenschreibweise verboten ist und wie viele Stellen ein Verbraucher höchstens akzeptiert. Ein JSON-String verhindert die binäre Umwandlung im eigenen Dienst, hält aber Browser, Message-Mapper oder Analyselader nicht davon ab, ihn später in eine Gleitkommazahl umzuwandeln. Vertragstests müssen die echte Verbrauchergrenze überschreiten.

Rundung geschieht an den Zielfeldgrenzen

Millionen Zeilen als Ganzes behandeln
Die Plattform verarbeitet Systeme mit mehr als einer Million Zeilen samt Abhängigkeiten der Geldlogik.

COBOL bindet Rundung an Rechenanweisungen und Zielfelder. Wer nur den Endtyp, aber nicht jeden Skalenübergang nachbildet, erhält andere Cents. Ob die Klausel ROUNDED vorhanden ist, gehört zum beobachtbaren Verhalten.

Betrachten Sie eine Ratenberechnung:

01  WS-BASE       PIC S9(7)V99 COMP-3.
01  WS-RATE       PIC S9(2)V9(5) COMP-3.
01  WS-FEE        PIC S9(7)V99 COMP-3.

COMPUTE WS-FEE ROUNDED = WS-BASE * WS-RATE

Mit WS-BASE = 100.00 und WS-RATE = 0.01255 ist das exakte Produkt 1.2550000. Die Übertragung in Skala zwei ergibt mit gewöhnlicher Rundung zum nächsten Wert 1.26. Ohne ROUNDED werden verworfene Stellen abgeschnitten, sodass 1.25 gespeichert wird. Eine moderne Neuentwicklung mit globaler kaufmännischer Rundung kann bei manchen Bindewerten 1.26 und bei anderen 1.24 erzeugen, während der gewählte COBOL-Modus von null weg runden würde. Leiten Sie die tatsächliche Regel aus Compiler, Dialekt, Anweisung und Tests ab.

Verstreuen Sie keine round(2)-Aufrufe im übersetzten Geschäftscode. Modellieren Sie Neuskalierung als Operation mit benannter Semantik:

rescale(value, targetScale, mode)
modes: truncate, nearestAway, nearestEven, floor, ceiling

Kennzeichnen Sie dann jede Kante im rekonstruierten Fluss, an der Skala verloren geht. Dazu gehören arithmetische Zielfelder, MOVE-Anweisungen, Aufrufe mit engeren Parametern, Datenbankzuweisungen, Berichtsfelder und ausgehende Datensätze. Ein MOVE kann die Cents verlieren, obwohl die eigentliche Rechnung vier Nachkommastellen behielt.

Beim Abschneiden zählt das Vorzeichen. Abschneiden von -1.259 in Richtung null ergibt -1.25; mathematisches Abrunden ergibt -1.26. Sprachen verhalten sich bei negativer Division und Rest unterschiedlich. Testen Sie die Implementierung, statt anzunehmen, ein Ganzzahltrick verhalte sich wie COBOL.

Größenfehler gehören ebenfalls zum Ergebnis. ON SIZE ERROR kann verzweigen, wenn das Zielfeld den Wert nicht aufnehmen kann. Andere Pfade schneiden möglicherweise führende Stellen ab oder verlassen sich auf Compilerverhalten, das die Neuentwicklung ablehnen sollte. Der Paritätsdatensatz muss festhalten, ob die Quelle den Größenfehlerzweig nahm, nicht nur den gespeicherten Zahlenwert.

Eine Rechenanweisung kann mehrere Zielfelder mit verschiedenen PICTURE-Klauseln besitzen. COBOL wendet das Ergebnis entsprechend der Kapazität und Rundungsklausel jedes Zielfelds an. Eine Umstrukturierung, die einmal in das engste Ziel rechnet und in die anderen kopiert, verliert Informationen früher als die Quelle. Rechnen Sie mit der rekonstruierten Zwischengenauigkeit und skalieren Sie anschließend für jede Zielkante getrennt.

Währungsregeln können etwas anderes als zwei Dezimalstellen verlangen. Bargeldrundung, Währungen ohne Untereinheit und Rechnungen mit Centbruchteilen kommen vor, doch das Copybook wählt keine Richtlinie. Rekonstruieren Sie die Regel aus Anweisungen, Tabellen und Ausgaben. Hängen Sie nicht eine allgemeine Methode Money.round() an und hoffen Sie, dass jeder Aufruf dasselbe Ergebnis will.

Zwischengenauigkeit verändert das Ergebnis

Auswertungsreihenfolge, Compileroptionen für Arithmetik und Definitionen temporärer Felder können den letzten Cent ändern, selbst wenn Quelle und Ziel ausschließlich exakte Dezimaltypen verwenden. Exakte Arithmetik ist nicht grenzenlose Arithmetik.

Vergleichen Sie diese Formen:

A = roundToCents(BASE * RATE)
B = roundToCents(roundToScale4(BASE * RATE_PART_1) +
                 roundToScale4(BASE * RATE_PART_2))

Sie sind algebraisch verwandt, müssen aber numerisch nicht gleich sein. Die Quelle kann jede Komponente in ein Arbeitsfeld runden, bevor sie addiert. Eine Neuentwicklung, die den Ausdruck zusammenfasst und nur einmal rundet, verändert das Programm. COBOL-Arbeitsfelder vor festgestellter Parität wegzuoptimieren erzeugt zuverlässig kleine Unterschiede, deren Suche viel Zeit kostet.

Die Dokumentation zu IBM Enterprise COBOL unterscheidet ARITH(COMPAT) und ARITH(EXTEND). Die erste Option begrenzt Dezimaloperanden auf 18 Stellen, die zweite erlaubt bis zu 31 und ändert die Kapazität von Festkomma-Zwischenergebnissen. IBM warnt auch, dass NUMVAL angenäherte Werte einbeziehen kann und die Arithmetikoption Ergebnisse beeinflusst. Das erinnert an einen wichtigen Punkt: Ein Feld, das im Ruhezustand dezimal aussieht, kann bei der Umwandlung durch Gleitkomma- oder anders dimensionierte Zwischenwerte laufen.

Inventarisieren Sie Compiler- und Laufzeiteinstellungen jedes betroffenen Lademoduls. Derselbe Quelltext unter anderen Optionen ergibt nicht automatisch denselben ausführbaren Vertrag. Erfassen Sie ARITH, NUMPROC, TRUNC, Dialekt, Compilerversion und relevante Laufzeiteinstellungen. Fehlen Builddaten, erstellen Sie Prüfprogramme und führen Grenzwerte mit dem produktionskompatiblen Compiler aus.

Eine brauchbare Prüfmatrix enthält positive und negative Bindewerte, maximale Koeffizienten, null mit jedem akzeptierten Vorzeichen, Produkte mit einer zusätzlichen Zwischenstelle sowie Divisionen mit periodischem Dezimalergebnis. Speichern Sie Eingabebytes, DISPLAY-Ausgabe, Ergebnisbytes, Rückgabecodes und Zweigmarkierungen. Diese kleinen Programme beenden Streit darüber, was COBOL "normalerweise" tut, schneller als eine weitere Besprechung.

Bewahren Sie die Auswertungsreihenfolge bis zur ersten korrekten Version. Sobald die Paritätstests sauber bleiben, können Sie Ausdrücke einzeln vereinfachen. Jede Vereinfachung muss über aufgezeichneten Verkehr und erzeugte Grenzwerte beweisen, dass die Ausgaben gleich bleiben.

Ungültige numerische Daten gehören zur Migration

Vorzeichenbytes erklärbar machen
Der Paritätstest legt gepackte Vorzeichen, Overpunch, Ausgabebytes und Zweigunterschiede zur Prüfung offen.

Produktionsdateien enthalten oft Bytes, die ihren Copybooks widersprechen, und das alte Programm kann sie dulden, bis eine bestimmte Operation eine Prüfung erzwingt. Eine Neuentwicklung, die jeden Wert still bereinigt, kann ebenso falsch sein wie eine, die am ersten fehlerhaften Datensatz abstürzt.

IBM erklärt, dass der Compiler im Allgemeinen davon ausgeht, Daten entsprächen PICTURE und USAGE. NUMCHECK(ZON,PAC) kann numerische Prüfungen ergänzen, wenn gezonte oder gepackte Felder als Sender dienen. Zulässige Vorzeichenmengen können von NUMPROC und Installationsentscheidungen abhängen. Zwei Programme können deshalb denselben Datensatz lesen, den Defekt aber an verschiedenen Stellen zeigen: Das eine vergleicht das Feld numerisch, das andere verschiebt die übergeordnete Gruppe als Bytes.

Verfolgen wir einen Fehler. Ein eingehendes gepacktes Feld enthält 12 34 5A: gültige Ziffernnibbles, aber einen Vorzeichencode, den die aktive Richtlinie nicht akzeptiert. Das Nachtprogramm kopiert die enthaltende Gruppe in ein Archiv und läuft durch, weil es das Feld nie numerisch behandelt. Eine Monatssumme verwendet das Feld später als Sender, löst eine Datenexception oder numerische Prüfung aus und schickt den Datensatz in eine Bedienerwarteschlange. Eine Neuentwicklung, die jedes Feld sofort dekodiert, lehnt ihn beim Einlesen ab. Eine Neuentwicklung, die jedes Vorzeichen von A bis F akzeptiert, kann ihn summieren. Beide haben das Betriebsverhalten geändert.

Die richtige Antwort ist eine feldbezogene Kompatibilitätsrichtlinie mit Belegen:

  • Strenge Felder lehnen ungültige Ziffern, Füllwerte oder Vorzeichen sofort ab.
  • Aufgeschobene Felder behalten Rohbytes und werden an derselben semantischen Grenze wie in der Quelle dekodiert.
  • Bekannte geduldete Kodierungen erhalten ausdrückliche Decoderfälle und benannte Fixtures.
  • Abgelehnte Datensätze tragen Datensatzidentität, Feldname, Byteoffset und hexadezimale Eingabe.

Machen Sie Freizügigkeit nicht zur Voreinstellung. Führen Sie die Quelle zuerst mit verfügbaren Diagnosen in einer repräsentativen Umgebung aus, untersuchen Sie echte Dateien und finden Sie jeden Erzeuger. Fehlerhafte Daten belegen oft eine undokumentierte Schnittstelle und sind keine seltsame Mainframe-Gewohnheit.

Diese Unterscheidung verändert auch die Einführung. Eine numerische Abweichung bei gültigen Daten ist ein Fehler der Neuentwicklung. Ein neu entdeckter ungültiger Datensatz kann ein Quelldatenfehler, ein Erzeugerfehler oder ein beabsichtigter Kompatibilitätsunterschied sein. Das Team braucht getrennte Zähler und Verantwortliche, sonst wird das Paritäts-Dashboard zu einem Streit über eine einzige rote Summe.

Ein Paritätstest muss mehr als Summen vergleichen

Mehr als Arithmetik neu schreiben
CodeHero liest jede Sprache im Bestand parallel, samt Jobs und Schnittstellen rund um COBOL.

Ein Paritätstest sollte identische Transaktionen durch Quelle und Ziel wiedergeben und erst Feldausgaben, Verzweigungen, Fehler und serialisierte Bytes vergleichen, bevor er Stapelsummen prüft. Gleiche Aggregate können zwei entgegengesetzte Fehler verdecken.

Aufgezeichneter Produktionsverkehr liefert realistische Kombinationen, deckt numerische Grenzen aber selten ab. Ergänzen Sie erzeugte Fälle rund um jeden rekonstruierten Vertrag:

  • null, negative null, Minimum, Maximum und eine Einheit außerhalb des gültigen Bereichs;
  • jeden Halbwert an jeder Operation mit Skalenverlust, auf beiden Seiten von null;
  • jeden akzeptierten und abgelehnten gepackten oder überpunchten Vorzeichencode;
  • ungültige Ziffern, Füllwerte, zu kurze Datensätze und Kodierungsfehler;
  • Werte, die erst nach Multiplikation oder Skalenabgleich überlaufen.

Erfassen Sie für jeden Fall eine Vergleichshülle wie diese:

{
  "case": "fee-negative-half-cent",
  "inputHex": "00001000C000125C",
  "source": {
    "coefficient": "-126",
    "scale": 2,
    "status": "OK",
    "outputHex": "0000126D"
  },
  "target": {
    "coefficient": "-126",
    "scale": 2,
    "status": "OK",
    "outputHex": "0000126D"
  }
}

Die genaue Hülle wird variieren. Strings für Koeffizienten, die den sicheren Ganzzahlbereich eines Verbrauchers überschreiten können, sind jedoch Absicht. Hexadezimalfelder machen Unterschiede bei Vorzeichen und Füllwerten sichtbar. Der Status enthält Quellzweige wie ON SIZE ERROR, nicht nur Prozess-Endecodes.

Weicht ein Stapel mit einer Million Datensätzen um einen Cent ab, halbieren Sie zuerst nach Datensatzbereich, dann nach Transaktion, Feld und Rechenkante. Protokollieren Sie unskalierte Operanden, Skalen, Operation, Zwischengenauigkeit und Neuskalierungsmodus. Ein Trace mit nur expected 19.42, got 19.43 überlässt die schwere Arbeit im schlechtesten Moment einem Menschen.

Führen Sie Vergleiche auf drei Ebenen aus. Numerische Parität prüft Koeffizienten nach Abgleich der erklärten Skalen. Verhaltensparität prüft Entscheidungen, Exceptions und nachgelagerte Datensätze. Byteparität prüft Schnittstellen mit festem Format, die identisch bleiben müssen. Verlangen Sie keine Byteparität von einer neu entworfenen API, deren Formatierung sich sicher ändern darf. Begnügen Sie sich nicht mit numerischer Parität bei einem regulierten Extrakt, dessen Verbraucher Spalten über Byteoffsets liest.

Behandeln Sie Vergleichsausnahmen als Code. Wenn Zeitstempel, Sequenznummern oder bewusst neu entworfene Formatierung abweichen, normalisieren Sie nur diese benannten Felder und prüfen die Regel wie Produktionslogik. Eine breite Option "Leerraum ignorieren" kann eine bedeutsame Vorzeichenposition oder Spaltenverschiebung ausradieren. Jede Ausnahme braucht einen Verantwortlichen und eine Ablaufbedingung.

Freigabeschranken sollten Abweichungsklassen statt einer gemischten Erfolgsquote melden. Null unerklärte Geldabweichungen ist eine vernünftige Schranke, auch wenn genehmigte Schnittstellenänderungen verbleiben. Halten Sie die Quelle wiedergabefähig, bis jede Abweichung ein Fixture, eine Entscheidung und einen Regressionstest besitzt. Sonst kehrt derselbe Cent nach einer unabhängigen Optimierung zurück.

CodeHero verwendet dafür aufgezeichneten Produktionsverkehr in einem Paritätstest: Kompilierbare Übersetzung beweist nicht, dass Dezimalverhalten erhalten blieb. Automatisieren Sie bei großen Beständen Feldkatalog und Trace-Erzeugung, damit Prüfer Abweichungen untersuchen statt Copybooks abzuschreiben.

Der Migrationsvertrag muss prüfbar sein

Der fertige numerische Vertrag muss einen Zielbetrag zurück zu den Quellbytes und vorwärts durch jede Rundungsgrenze verfolgen lassen. Lebt er nur im Kopf des letzten COBOL-Betreuers, ist die Neuentwicklung nicht bereit.

Verlangen Sie diese Punkte vor der Umschaltung eines Geldpfads:

  1. Jedes numerische Quellfeld hat qualifizierten Namen, PICTURE, USAGE, Bytebereich, Kodierung, Genauigkeit, Skala und Vorzeichenrichtlinie.
  2. Jeder Zieltyp hat einen schriftlichen Bereichsnachweis einschließlich Zwischenwerten.
  3. Jeder Skalenverlust nennt Rundungs- oder Abschneidemodus und die Quellanweisung, die ihn festlegt.
  4. Das Verhalten bei ungültigen Daten besitzt Fixtures für akzeptierte, abgelehnte, aufgeschobene und negative Nullfälle.
  5. Die Paritätssuite vergleicht numerische, verhaltensbezogene und Byteergebnisse, wo die jeweilige Ebene zählt.

Bewahren Sie diesen Vertrag neben dem Ersatzcode auf und erzeugen Sie so viel wie möglich automatisch. Prüfer müssen eine Zuordnung wie S9(11)V9(6) -> int64 mit den größten Operanden anfechten und die Antwort sehen können. Eine Notiz "passt" reicht nicht.

Behalten Sie nach der Umschaltung Grenzmetriken, die Dekodierungsfehler, Überläufe, Skalenreduktionen und Paritätsabweichungen trennen. Schreiben Sie keine Kontowerte oder kompletten Datensätze in allgemeine Logs. Feldbezeichner, Operationsbezeichner, sichere Datensatzreferenzen und maskierte Koeffizienten reichen meist, um einen Fehler zu finden, ohne ein neues Datenproblem zu schaffen.

Der Maßstab für Geld ist absichtlich streng. Jeder Cent braucht eine Herkunft: Quellziffern, Vorzeichendeutung, Skala, Zwischenoperationen und abschließende Neuskalierungsregel. Kann die Neuentwicklung diese Kette für einen Fehler zeigen und über den gesamten Datenbestand beweisen, darf die alte Darstellung verschwinden, ohne ihr Verhalten mitzunehmen.

FAQ

Was ist COMP-3 in COBOL?

COMP-3 ist eine gepackte Dezimaldarstellung. Sie legt in den meisten Bytes zwei Dezimalziffern ab und reserviert das letzte Halbbyte für ein Vorzeichen, während die PICTURE-Klausel Genauigkeit und Skala liefert.

Wie viele Bytes belegt ein COMP-3-Feld?

Für n Dezimalziffern brauchen Sie floor(n / 2) + 1 Bytes. Das zusätzliche Halbbyte trägt das Vorzeichen, und bei gerader Ziffernzahl bleibt ein führendes Füllnibble, das trotzdem geprüft werden sollte.

Belegt das V in einer COBOL-PICTURE ein Byte?

Nein. V markiert einen angenommenen Dezimalpunkt ohne Speicherplatz. S9(5)V99 speichert daher sieben Ziffern plus Vorzeichen und trägt Skala zwei.

Kann man COBOL-Geldwerte nach double oder float migrieren?

Nicht sicher. Binäres Gleitkomma kann viele Dezimalbrüche nicht exakt darstellen, und schon eine vorübergehende Umwandlung kann die Rundung verändern, auch wenn später wieder ein Dezimaltyp folgt.

Ist Signed Overpunch dasselbe wie COMP-3?

Nein. Overpunch bettet das Vorzeichen in die Zonenbits eines DISPLAY-Ziffernbytes ein. COMP-3 speichert Dezimalziffern in Nibbles und nutzt das letzte Nibble für das Vorzeichen.

Welches Vorzeichen-Nibble bedeutet bei gepackten Dezimalzahlen negativ?

D ist das übliche negative Vorzeichen-Nibble, C bedeutet gewöhnlich positiv und F erscheint häufig bei vorzeichenlosen Daten. Behandeln Sie die zulässige Menge als Compiler- und Schnittstellenrichtlinie, denn Produktionsdaten können weitere Codes enthalten.

Rundet COBOL Geldbeträge automatisch?

Es gibt keine allgemeine Regel. Die Rundung hängt von Anweisung, Zielfeld und dem Auftreten von ROUNDED ab. Skalenverlust ohne diese Klausel schneidet üblicherweise ab.

Warum kann exakte Dezimalarithmetik trotzdem von COBOL abweichen?

Auch exakte Typen besitzen begrenzte Genauigkeit, Auswertungsreihenfolge und Neuskalierungsregeln. Ein anderes temporäres Feld, zusammengefasste Ausdrücke oder einmaliges statt komponentenweises Runden können den letzten Cent verschieben.

Wie sollte negative null migriert werden?

Legen Sie fest, ob Sie sie normalisieren, ein Vorzeichenflag behalten oder die ursprünglichen Bytes für Rundläufe aufbewahren. Numerische Gleichheit entscheidet keine vorzeichenabhängige Verzweigung und keine Festformatausgabe.

Was beweist die Korrektheit einer COBOL-Neuentwicklung für Geld?

Spielen Sie dieselben Eingaben durch beide Systeme und vergleichen Sie Koeffizienten, Skalen, Verzweigungen, Fehler und erforderliche Ausgabebytes. Ergänzen Sie erzeugte Grenzfälle, weil aufgezeichneter Verkehr selten jeden Bindewert, Überlauf, Vorzeichencode oder fehlerhaftes Feld enthält.